我正在使用SQLAlchemy和我喜欢的Django ORM是我可以实现的管理器来覆盖对象的初始查询。
SQLAlchemy中是否存在类似的内容?当我执行以下操作时,我总是要排除具有“visible = False”的项目:
session.query(BlogPost).all()
有可能吗?
谢谢!
答案 0 :(得分:7)
编辑:原始版本几乎可以使用。以下版本实际上有效。
听起来你正在尝试做的是安排查询实体不是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)
相同的结构并提取“语句”。但是,您实际上并不希望它绑定到会话,因此请直接调用该类。
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
,可以正常更新和保存。< / p>
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调用中遗漏了一些缺少的[]
,它希望列在一个序列中。当对select
使用mapper
语句时,sqlalchemy坚持声明该语句为别名,以便将其命名为(SELECT .... ) AS some_subselect_alias_5
答案 1 :(得分:0)
你可以这样做。
session.query(BlogPost).filter_by(visible=True)
它应该只为您提供所需的帖子。