Python 使用SQLAlchemy ORM查询其他数据

Python 使用SQLAlchemy ORM查询其他数据,python,sqlalchemy,flask-sqlalchemy,Python,Sqlalchemy,Flask Sqlalchemy,假设我有一个博客系统的简单模型: class Blog(db.Model): __tablename__ = 'blog' id = db.Column(db.BigInteger, primary_key=True) posts = db.relationship('Post', backref='blog', lazy='dynamic') class Post(db.Model): __tablename__ = 'post' id = d

假设我有一个博客系统的简单模型:

class Blog(db.Model):

    __tablename__ = 'blog'

    id = db.Column(db.BigInteger, primary_key=True)
    posts = db.relationship('Post', backref='blog', lazy='dynamic')

class Post(db.Model):

    __tablename__ = 'post'

    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String())
我使用的是Flask SQLAlchemy,所以语法看起来可能有点不同,不过映射非常简单

是否可以获取所有博客以及帖子数量?因为现在对列表进行迭代时,每次迭代都会执行一个额外的查询,而这并不能真正扩展。在SQL中非常简单:

SELECT b.*, COUNT(p)
FROM blog b
    JOIN post p ON(b.id = p.blog_id)
GROUP BY b.id;
但是炼金术是如何做到的呢?我最好有两个选择:

在查询时指定 在模型本身中创建一个虚拟属性以始终使用它,例如Hibernate调用此
我想我遗漏了正确的术语,因为我在Google上找不到任何东西。

见下文,代码应该能回答您的两个问题。第二部分的答案是使用


看起来很有希望,我晚上试试看。你知道你是否可以把计数分配给Blog的一个属性,而不是返回一个元组或其他什么吗?我知道我可以自己循环,但也许SQLAlchemy可以自动循环?简单查询是问题的第一部分。其余部分使用hybrid_属性,这正是Blog类上的一个属性,正如您从代码中看到的。没错,它适用于hybrid属性。但它是否也适用于简单查询?
class Blog(db.Model):
    __tablename__ = 'blog'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    posts = db.relationship('Post', backref='blog', lazy='dynamic')

    @hybrid_property
    def num_posts(self):
        # return len(self.posts)  # use if relationship is *not* dynamic
        return self.posts.count()

    @num_posts.expression
    def _num_posts_expression(cls):
        return (db.select([db.func.count(Post.id)])
                .where(Post.post_id == cls.id)
                .label("num_posts")
                )


class Post(db.Model):
    __tablename__ = 'post'

    id = db.Column(db.Integer, primary_key=True)
    post_id = db.Column(db.ForeignKey(Blog.id))
    title = db.Column(db.String())


def test():
    with app.app_context():
        db.drop_all()
        db.create_all()

        def create_test_data():
            blogs = [
                Blog(name="empty",),
                Blog(name="geo",
                     posts=[
                         Post(title='west'),
                         Post(title='east'),
                         Post(title='north'),
                         Post(title='south'),
                     ]),
                Blog(name="food",
                     posts=[
                         Post(title='sour'),
                         Post(title='sweet'),
                     ]),
            ]
            db.session.add_all(blogs)
            db.session.commit()

        create_test_data()


        # simple query
        q = (db.session.query(Blog, db.func.count(Post.id).label("num_posts"))
             .outerjoin(Post, Blog.posts)
             .group_by(Blog.id)
             )
        for b, num_posts in q:
            print(b, num_posts)
        print("-"*80)


        # Using hybrid_attribute
        # num_posts is fetched later
        q = (db.session.query(Blog))
        for b in q:
            print(b)
            print(b.num_posts)
        print("-"*80)

        # num_posts is fetched with the query
        q = (db.session.query(Blog, Blog.num_posts))
        for b in q:
            print(b)
            print(b.num_posts)
        print("-"*80)