6

鉴于这种多对多关系:

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 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)中的特定列,那么您在表达式中的哪个位置说“我仍然想要标签”?

现在它并不那么重要,但我认为知道它会很有用。或者甚至知道这是不可能的。

4

2 回答 2

7

我假设您想对关系使用急切加载。您可以通过在与orlazy的关系中设置关键字参数来实现:'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部分和关系加载技术

于 2013-01-16T12:06:11.890 回答
0

SQLAlchemy 会在您访问它时自动加载该post.tags属性,因此您只需要加载您想要的所有帖子。

db.Column('tag_id', db.Integer, db.ForeignKey('quotes.id'),)

quotes.id是错字吗?

于 2013-01-16T07:04:17.697 回答