SQLAlchemy选择所有多对多关系对象作为列表

Ell*_*t C 6 python sqlalchemy flask flask-sqlalchemy

鉴于这种多对多的关系:

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)
Run Code Online (Sandbox Code Playgroud)

您将如何构造查询以选择所有帖子,包括可关联的Tag对象的可迭代列表?

期望的查询结果结构:

[ <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",    []> ]
Run Code Online (Sandbox Code Playgroud)

Jinja模板中所需的结果使用示例:

{% for post in posts %}
    {{ post.text }}
    <hr>
    {% for tag in post.tags %}
        {{ tag.name }}, 
    {% endfor %}
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

编辑:

尝试扩展查询时,标记将不再包含在内.查看下面的查询失败:

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,)
Run Code Online (Sandbox Code Playgroud)

编辑2:

所以这个查询效果很好:

posts = db.session.query(Post, User.name.label('author')).join(User)\
            .options(db.joinedload(Post.tags))\
            .order_by(Post.created.desc()).limit(5)
Run Code Online (Sandbox Code Playgroud)

但如果我想对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)
Run Code Online (Sandbox Code Playgroud)

它开始快速崩溃:

ArgumentError: Query has only expression-based entities - can't find property named 'tags'.
Run Code Online (Sandbox Code Playgroud)

所以我尝试添加标签:

# 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)
Run Code Online (Sandbox Code Playgroud)

哪个仍然失败.

因此,如果您只想要父对象(Post)中的特定列,您在表达式中的位置说"我还想要标记"吗?

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

Aud*_*kas 7

我假设你想使用渴望加载关系.你可以做到这一点通过设置lazy在你们的关系关键字参数'joined''subquery':

class Post(db.Model):
    # ...
    tags = db.relationship('Tag', secondary=tagmap, backref='posts',
                           lazy='joined')    # Or lazy='subquery'
Run Code Online (Sandbox Code Playgroud)

或者您可以按查询设置它:

q = Post.query.options(db.joinedload(Post.tags)).all()
# Or db.subqueryload(Post.tags)
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请参阅ORM教程和关系加载技术的Eager Loading部分.