我正在使用 SQLAlchemy,我喜欢 Django ORM 的地方是我可以实现的管理器来覆盖对象的初始查询。
SQLAlchemy 中有这样的东西吗?当我做类似的事情时,我想总是排除具有“visible = False”的项目:
session.query(BlogPost).all()
这可能吗?
谢谢!
最佳答案
编辑:原始版本几乎可以正常工作。以下版本实际有效。
听起来您想要做的是将查询实体安排为 SELECT table.* FROM table
以外的实体。在sqlalchemy中,你可以map any "selectable"上课;但是,有一些警告;如果 selectable 不是表格,插入数据可能会很棘手。像这样的方法是一个可行的解决方案。您可能确实希望将常规表映射为允许插入,因此第一部分是完全正常的表、类和映射器。
blog_post_table = Table("blog_posts", metadata,
Column('id', Integer, primary_key=True),
Column('visible', Boolean, default=True),
...
)
class BlogPost(object):
pass
blog_post_mapper = mapper(BlogPost, blog_post_table)
或者,如果您使用的是声明式扩展,那么它们都是一个
class BlogPost(Base):
__tablename__ = 'blog_posts'
id = Column(Integer, primary_key=True)
visible = Column(Boolean, default=True)
现在,我们需要一个select
表达式来表示可见的帖子。
visible_blog_posts_expr = sqlalchemy.sql.select(
[BlogPost.id,
BlogPost.visible]) \
.where(BlogPost.visible == True) \
.alias()
或者,由于命名所需查询的所有列很乏味(更不用说违反 DRY),您可以使用与 session.query(BlogPost)
相同的构造并提取'陈述'。不过,您实际上并不希望它绑定(bind)到 session ,因此直接调用该类。
visible_blog_posts_expr = \
sqlalchemy.orm.Query(BlogPost) \
.filter(BlogPost.visible == True) \
.statement \
.alias()
我们也绘制了它。
visible_blog_posts = mapper(BlogPost, visible_blog_posts_expr, non_primary=True)
然后您可以使用 visible_blog_posts
映射器代替 BlogPost
和 Session.query
,您仍然会得到 BlogPost
,可以正常更新和保存。
posts = session.query(visible_blog_posts).all()
assert all(post.visible for post in posts)
对于这个特定的例子,显式使用mapper
和声明式扩展没有太大区别,您仍然必须为非主映射调用mapper
。充其量,它允许您键入 SomeClass.colname
而不是 some_table.c.colname
(或 SomeClass.__table__.colname
,或 BlogPost.metadata.tables[BlogPost.__tablename__]
或 ... 等等)。
我在原始示例中犯的错误,现在已更正。我在调用 sqlalchemy.sql.select 时遗漏了一些 []
,它希望列按顺序排列。当对 mapper
使用 select
语句时,sqlalchemy 坚持该语句是别名的,以便它可以命名为 (SELECT .... ) AS some_subselect_alias_5
关于python - SqlAlchemy 的 models.Manager 的等价物,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6606745/