是否有一种“Pythonic”方式(我的意思是,没有“纯 SQL”查询)来使用 SQLAlchemy 定义 SQL 视图?
原文由 Thibaut D. 发布,翻译遵循 CC BY-SA 4.0 许可协议
是否有一种“Pythonic”方式(我的意思是,没有“纯 SQL”查询)来使用 SQLAlchemy 定义 SQL 视图?
原文由 Thibaut D. 发布,翻译遵循 CC BY-SA 4.0 许可协议
斯蒂芬的回答很好,涵盖了大多数基础,但让我不满意的是缺乏与 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__)
创建视图:
_在初始化数据库时执行,例如在 createall() 调用之后。
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() 调用期间自动删除。
这显然是一个非常 hacky 的解决方案,但在我看来,它是目前最好的、最干净的解决方案。这几天我测试了它,没有遇到任何问题。我不确定如何添加关系(在那里遇到问题),但这并不是真正必要的,如上面的查询所示。
如果有人有任何意见,发现任何意想不到的问题,或者知道更好的做事方式,请发表评论或让我知道。
这是在 SQLAlchemy 1.2.6 和 Python 3.6 上测试的。
原文由 fgblomqvist 发布,翻译遵循 CC BY-SA 3.0 许可协议
1 回答9.7k 阅读✓ 已解决
2 回答5.4k 阅读✓ 已解决
2 回答3.7k 阅读✓ 已解决
3 回答4.5k 阅读
3 回答1.5k 阅读✓ 已解决
4 回答1.5k 阅读✓ 已解决
2 回答1.6k 阅读✓ 已解决
更新: SQLAlchemy 现在 在这个主题上有一个很好的使用方法,我推荐。它涵盖了最新的不同 SQL Alchemy 版本,并具有 ORM 集成(请参阅此答案下方的评论和其他答案)。如果您查看版本历史记录,您还可以了解为什么使用
literal_binds
是不确定的(简而言之:绑定参数应该留给数据库),但仍然可以说任何其他解决方案会让大多数用户食谱不开心。我主要出于历史原因留下以下答案。原始答案: 据我所知,不支持开箱即用地创建(只读非物化)视图。但是在 SQLAlchemy 0.7 中添加此功能非常简单(类似于我在 此处 给出的示例)。您只需要编写一个 编译器扩展
CreateView
。使用此扩展,您可以编写(假设t
是一个包含列id
的表对象)这是一个工作示例:
如果你愿意,你也可以专门研究一种方言,例如