2016-04-10 12 views
0

私は2つのテーブルitemsgamesを持っています。参加したテーブルからデータを取得する方法

@app.route('/collection/<username>/<int:page>/<platform>/<path:path>')  
def collection(username, page=1, platform='DMG', path=None): 
    # first I get the user by his username 
    user = User.query.filter_by(username=username).first() 
    # then I get all items form the user and related games 
    items = user.items.join(Game) 
    # until now it works perfectly fine   
    # now I would like to obtain all titles from the joined table games 
    game_titles = items.filter(Game.title).all() 
    # but unfortunately I get only an empty list 

何が欠けていますか?

ここに私のモデル:

class Game(db.Model): 
    __tablename__ = 'games' 
    id = db.Column(db.Integer, primary_key=True) 
    title = db.Column(db.String(64), index=True) 
    publisher = db.Column(db.String(32), index=True) 
    region = db.Column(db.String(3), index=True) 
    code_platform = db.Column(db.String(3), index=True) 
    code_identifier = db.Column(db.String(4), index=True) 
    code_region = db.Column(db.String(3), index=True) 
    code_revision = db.Column(db.String(1)) 
    code = db.Column(db.String(16), index=True, unique=True) 
    year = db.Column(db.Integer) 

    user_id = db.Column(db.Integer, db.ForeignKey('users.id')) 
    items = db.relationship('Item', backref='game', lazy='dynamic') 

    def __repr__(self): 
     return '<Game %r>' % (self.title) 


class Item(db.Model): 
    __tablename__ = 'items' 
    id = db.Column(db.Integer, primary_key=True) 
    code = db.Column(db.String(8), index=True) 
    cart = db.Column(db.Boolean) 
    box = db.Column(db.Boolean) 
    manual = db.Column(db.Boolean) 

    user_id = db.Column(db.Integer, db.ForeignKey('users.id')) 
    game_id = db.Column(db.Integer, db.ForeignKey('game.id')) 

    def __repr__(self): 
     return '<Collection %r>' % (self.user_id) 
+0

「すべてのゲームタイトルをフィルタリングする」とはどういう意味ですか? – univerio

+0

@univerioテーブル 'items'にリンクされているテーブル 'games'のすべてのタイトルが必要です。 – ericMTR

答えて

1

2つのオプションがあります。これをより効率的にするために

game_titles = [i.game.title for i in user.items] 

、あなたがjoinedload最適化適用することができます:SQLAlchemyのORMを使用して、あなたが気にすべてのタイトル(と何もしている場合代わり

game_titles = [i.game.title for i in user.items.options(joinedload(Item.game))] 

を、あなたはSQLAlchemyのコアを使用することができます

01:):あなたがすべてでユーザーを気にしない場合

game_titles = user.items.join(Item.game).with_entities(Game.title).all() 

あなたも、完全にユーザーをフェッチスキップすることができます

game_titles = User.query.join(User.items).join(Item.game).filter(User.username == username).with_entities(Game.title).all() 

.with_entitiesdb.session.query(...)は、あなたが最初に想定していたものに反しprojection operator、に対応し、一方、脇、.filter.filter_byは、リレーショナル代数にselection operatorに対応しています。

+0

ありがとうございました。どちらのオプションも完璧に動作します。そして別のものだけを得るために、私は 'user.items.join(Game.with_entities(Game.code_platform).distinct()。all()'のように '.distinct()'を適用します。また、SQLAlechemy ORMを使用してこれを行うことも可能でしょうか? – ericMTR

+0

@ericMTR直接ではありません。 ORM( 'list(set(game_titles))')を使用する場合は、Pythonで重複排除を行う必要があります。 – univerio

1

このような何か試してみてください:基本的に

items.join(Game).options(joinedload(Item.game, innerjoin=True)) 

を、あなたはどこinnerjoin力がそれだけでこれを行うには、ゲームに参加すると、明示的にそれをロードしていますあなたが参加しているテーブルに記載されているゲーム(アイテム)

+0

あなたの提案をありがとう。それは部分的に働く。 'games = items.filter_by(title = 'アドベンチャーアイランド')all()'のような特定のゲームをフィルタリングすることができます。しかし、私はまだすべてのゲームをすぐに手に入れることができます。 'games = items.filter(Game.title).all()'しようとすると空リストになります。ここに提案はありますか? – ericMTR

+0

@ericMTR 'filter'は、「列の完全なセットを取り出し、必要な列のみにフィルタリングする」という意味ではありません。これは、「**行**のフルセットを取得し、指定した基準に一致する**行**のみにフィルタリングする」ことを意味します。 – univerio

+0

@univerioだから、私が望む特定の列のすべてのアイテムを取得するにはどうしたらよいでしょうか? 'items.join(Game).options(joinedload(Item.game、innerjoin = True))'に基づいて**テーブル**ゲーム**から列** title **のすべての項目を欲しいですか? – ericMTR

関連する問題