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)