2013-01-16 8 views
5

など、多くの関係オブジェクトへのすべての多くと選択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) 

どのように関連するタグオブジェクトの反復可能なリストを含むすべての記事を選択するクエリを構築するのでしょうか?

目的のクエリ結果の構造:神社テンプレート内

[ <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", []> ] 

例所望の結果の使用:

{% for post in posts %} 
    {{ post.text }} 
    <hr> 
    {% for tag in post.tags %} 
     {{ tag.name }}, 
    {% endfor %} 
{% endfor %} 

編集

クエリを拡張しようとすると、タグが停止含まれています。編集2

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,) 

だから、このクエリは素晴らしい作品:以下失敗したクエリを参照してください

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

が、私は選択のポストの列に関する選択できるようにする場合:

# 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)の特定の列だけが必要な場合は、式のどこで「タグはまだ必要ですか」を指定します。

今はそれほど重要ではありませんが、知っておくと便利だと思いました。あるいはそれが不可能であることを知っている。

答えて

6

熱心な負荷を使用したいと考えています。

q = Post.query.options(db.joinedload(Post.tags)).all() 
# Or db.subqueryload(Post.tags) 

はORMのチュートリアルとRelationship Loading TechniquesのためのEager Loading一部を参照してください。

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

それとも、クエリごとに設定することができます:あなたはどちらかということ'joined''subquery'にあなたの関係でlazyキーワード引数を設定することによって達成することができます詳細はこちら

+0

美しい、ありがとうございました! – Elliott

+0

'joinedval'ステートメントをもっと複雑なクエリに含めるにはどうすればいいですか?例えば' .values() 'を使っているのですか? (私の質問をサンプルクエリで更新しました) – Elliott

+0

まず、あなたの 'values()'引数に 'Post.tags'を使用していませんが、私はそれが関係少なくとも、私の他のコードでは簡単なテストではありません。複数のテーブルから値を照会する場合は、この場合、 'db.session.query(...)'を使用しない方が良いでしょうか? –

0

SQLAlchemyは、アクセス時にpost.tagsプロパティを自動的にロードするので、必要なすべての投稿をロードするだけで済みます。

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

そのquotes.idタイプミスですか?

+0

はい、これはタイプミスでしたが、私は外部キーを修正して、今は意味をなさないようにしました。 – Elliott

関連する問題