相当于model.Manager for SqlAlchemy

Cyr*_* N. 6 python django sqlalchemy

我正在使用SQLAlchemy和我喜欢的Django ORM是我可以实现的管理器来覆盖对象的初始查询.

SQLAlchemy中是否存在这样的内容?当我执行以下操作时,我总是要排除具有"visible = False"的项目:

session.query(BlogPost).all()
Run Code Online (Sandbox Code Playgroud)

可能吗?

谢谢!

Sin*_*ion 7

编辑:原始版本几乎工作.以下版本实际上有效.

听起来你正在尝试做的是安排查询实体不是SELECT table.* FROM table.在sqlalchemy中,您可以将任何"可选"映射到类; 但是有一些警告; 如果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)
Run Code Online (Sandbox Code Playgroud)

或者,如果您使用声明性扩展,那么它们都将是一个

class BlogPost(Base):
    __tablename__ = 'blog_posts'
    id = Column(Integer, primary_key=True)
    visible = Column(Boolean, default=True)
Run Code Online (Sandbox Code Playgroud)

现在,我们需要一个select表达式来表示可见的帖子.

visible_blog_posts_expr = sqlalchemy.sql.select(
        [BlogPost.id,
         BlogPost.visible]) \
    .where(BlogPost.visible == True) \
    .alias()
Run Code Online (Sandbox Code Playgroud)

或者,由于命名所需查询的所有列是繁琐的(更不用说违反DRY),您可以使用相同的构造session.query(BlogPost)并提取"语句".但是,您实际上并不希望它绑定到会话,因此请直接调用该类.

visible_blog_posts_expr = \
    sqlalchemy.orm.Query(BlogPost) \
    .filter(BlogPost.visible == True) \
    .statement \
    .alias()
Run Code Online (Sandbox Code Playgroud)

我们也会映射它.

visible_blog_posts = mapper(BlogPost, visible_blog_posts_expr, non_primary=True)
Run Code Online (Sandbox Code Playgroud)

然后你可以使用visible_blog_postsmapper而不是BlogPosts Session.query,你仍然会得到BlogPost,可以正常更新和保存.

posts = session.query(visible_blog_posts).all()
assert all(post.visible for post in posts)
Run Code Online (Sandbox Code Playgroud)

对于这个特定的例子,显式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