鉴于这种多对多的关系:
tagmap = db.Table('tagmap', db.Model.metadata,
db.Column('post_id', db.Integer, db.ForeignKey('posts.id'),
db.Column('tag_id', db.Integer, db.ForeignKey('tags.id'),)
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
text = db.Column(db.Text)
tags = db.relationship('Tag', secondary=tagmap, backref='posts')
class Tag(db.Model):
__tablename__ = 'tags'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
如何构建查询以选择所有帖子,包括相关标签对象的可迭代列表?
所需的查询结果结构:
[ <Post 1, "Blah", [<Tag "Goober">, <Tag "Mexico">]>,
<Post 2, "Daft Punk", [<Tag "French">]>,
<Post 3, "Slurpee", [<Tag "Diabetes">, <Tag "Tasty">, <Tag "Sugary">]>,
<Post 4, "Lasers", []> ]
Jinja模板中所需的结果使用示例:
{% for post in posts %}
{{ post.text }}
<hr>
{% for tag in post.tags %}
{{ tag.name }},
{% endfor %}
{% endfor %}
修改:
尝试扩展查询时,标记将不再包含在内。请参阅下面的查询失败:
Post.query.join(User)\
.options(db.joinedload(Post.tags))\
.order_by(Post.create_date.desc()).limit(5)\
.values(User.name.label('author'),
Post.create_date,
Post.text,)
编辑2 :
所以这个查询效果很好:
posts = db.session.query(Post, User.name.label('author')).join(User)\
.options(db.joinedload(Post.tags))\
.order_by(Post.created.desc()).limit(5)
但如果我想选择Post I中的列,请选择:
# I only need the post text, nothing else
posts = db.session.query(Post.text, User.name.label('author')).join(User)\
.options(db.joinedload(Post.tags))\
.order_by(Post.created.desc()).limit(5)
它开始快速崩溃:
ArgumentError: Query has only expression-based entities - can't find property named 'tags'.
所以我尝试重新添加标签:
# Yes, I know this is wrong
posts = db.session.query(Post.text, Post.tags, User.name.label('author'))\
.join(User)\
.options(db.joinedload(Post.tags))\
.order_by(Post.created.desc()).limit(5)
仍然失败。
因此,如果你只想要父对象(Post)中的特定列,你在表达式中说“我还想要标签”吗?
现在并不是那么重要,但我认为知道它会很有用。或者甚至知道这是不可能的。
答案 0 :(得分:7)
我假设你想使用渴望加载来建立关系。您可以通过在lazy
或'joined'
的关系中设置'subquery'
关键字参数来实现这一目标:
class Post(db.Model):
# ...
tags = db.relationship('Tag', secondary=tagmap, backref='posts',
lazy='joined') # Or lazy='subquery'
或者您可以按查询设置:
q = Post.query.options(db.joinedload(Post.tags)).all()
# Or db.subqueryload(Post.tags)
有关详细信息,请参阅ORM教程的Eager Loading部分和Relationship Loading Techniques。
答案 1 :(得分:0)
SQLAlchemy在您访问它时会自动加载post.tags
属性,因此您只需要加载所需的所有帖子。
db.Column('tag_id', db.Integer, db.ForeignKey('quotes.id'),)
那quotes.id
是错字吗?