Ответ Стефана хороший и охватывает большинство баз, но что меня не удовлетворило, так это отсутствие интеграции с остальной частью SQLAlchemy (ORM, автоматическое удаление и т. Д.). После нескольких часов экспериментов и объединения знаний из всех уголков интернета я придумал следующее:
import sqlalchemy_views
from sqlalchemy import Table
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.ddl import DropTable
class View(Table):
is_view = True
class CreateView(sqlalchemy_views.CreateView):
def __init__(self, view):
super().__init__(view.__view__, view.__definition__)
@compiles(DropTable, "postgresql")
def _compile_drop_table(element, compiler, **kwargs):
if hasattr(element.element, 'is_view') and element.element.is_view:
return compiler.visit_drop_view(element)
# cascade seems necessary in case SQLA tries to drop
# the table a view depends on, before dropping the view
return compiler.visit_drop_table(element) + ' CASCADE'
Обратите внимание, что я использую пакет sqlalchemy_views
, просто для упрощения вещей.
Определение вида (например, глобально, как ваши модели таблиц):
from sqlalchemy import MetaData, text, Text, Column
class SampleView:
__view__ = View(
'sample_view', MetaData(),
Column('bar', Text, primary_key=True),
)
__definition__ = text('''select 'foo' as bar''')
# keeping track of your defined views makes things easier
views = [SampleView]
Отображение видов (включить функциональность ORM):
Делать при загрузке приложения, перед любыми запросами и после настройки БД.
for view in views:
if not hasattr(view, '_sa_class_manager'):
orm.mapper(view, view.__view__)
Создание видов:
Делать при инициализации базы данных, например, после вызова create_all ().
from sqlalchemy import orm
for view in views:
db.engine.execute(CreateView(view))
Как запросить представление:
results = db.session.query(SomeModel, SampleView).join(
SampleView,
SomeModel.id == SampleView.some_model_id
).all()
Это вернет именно то, что вы ожидаете (список объектов, каждый из которых имеет объект SomeModel и объект SampleView).
Отбрасывание вида:
SampleView.__view__.drop(db.engine)
Он также автоматически сбрасывается при вызове drop_all ().
Это, очевидно, очень хакерское решение, но на мой взгляд, это лучшее и самое чистое решение на данный момент. Я проверял это в последние несколько дней, и у меня не было никаких проблем. Я не уверен, как добавить в отношения (столкнулся с проблемами там), но это на самом деле не нужно, как показано выше в запросе.
Если у кого-либо есть какие-либо сведения, если они обнаруживают какие-либо неожиданные проблемы или знают, как лучше поступить, оставьте комментарий или сообщите мне.
Это было проверено на SQLAlchemy 1.2.6 и Python 3.6.