2016-04-10 14 views
0

Ich habe zwei Tabellen items und games.So erhalten Sie Daten aus einer Tabelle, die verbunden wurde

@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 

Was fehlt?

Hier meine Modelle:

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

Was meinen Sie mit "alle Spieltitel filtern"? – univerio

+0

@univerio Ich möchte alle Titel in der Tabelle 'Spiele', die in der Tabelle 'Elemente' verknüpft sind. – ericMTR

Antwort

1

Du hast zwei Möglichkeiten. SQLAlchemy ORM:

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

Um dies effizienter zu gestalten, können Sie die joinedload Optimierung anwenden:

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

Alternativ können Sie SQLAlchemy Kern verwenden, wenn alle um dich kümmern sind die Titel (und nichts anderes):

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

Sie können sogar überspringen den Benutzer völlig holen, wenn Sie gar nicht über den Benutzer interessieren:

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

Als beiseite, .filter und .filter_by entsprechen die selection operator in relationalen Algebra, während .with_entities und db.session.query(...) zum projection operator entsprechen, im Gegensatz zu dem, was man ursprünglich angenommen hatte.

+0

Vielen Dank. Beide Optionen funktionieren einwandfrei. Und um nur die eindeutigen zu erhalten, würde ich '.distinct()' wie 'user.items.join (Spiel) .with_entities (Game.code_platform) .distinct(). All()' anwenden. Wäre es auch möglich, das mit SQLAlechemy ORM zu tun? – ericMTR

+0

@ericMTR Nicht direkt. Sie müssen die Deduplizierung in Python durchführen, wenn Sie das ORM verwenden ('list (set (game_titles))'). – univerio

1

Probieren Sie etwas wie folgt aus:

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

Im Wesentlichen sind Sie mit Spiel verbinden und es explizit laden, wo die innerjoin Kräfte es so zu tun, nur auf die Spiele, die in der Tabelle aufgelistet sind, mit der du dich verbindest (Artikel)

+0

Danke für Ihren Vorschlag. Es funktioniert teilweise. Ich kann bestimmte Spiele wie 'games = items.filter_by (title = 'Adventure Island'). All()' filtern. Aber ich kann immer noch alle Spiele auf einmal bekommen. Wenn ich 'games = items.filter (Game.title) .all()' versuche, bekomme ich eine leere Liste. Irgendwelche Vorschläge hier? – ericMTR

+0

@ericMTR 'filter' bedeutet nicht" nimm den vollen Spaltensatz und filtere ihn nur auf die Spalten, die ich haben möchte ". Es bedeutet "nimm den ganzen Satz von ** Zeilen ** und filtere ihn auf nur die ** Zeilen **, die den angegebenen Kriterien entsprechen". – univerio

+0

@univerio Also, wie könnte ich erreichen, alle Elemente einer bestimmten Spalte, die ich will, zu bekommen? Ich möchte alle Elemente in der Spalte ** Titel ** aus der Tabelle ** Spiele ** basierend auf 'items.join (Spiel) .options (jointload (Item.game, innerjoin = True))'? – ericMTR

Verwandte Themen