2010-12-21 1 views
2

Ich bin neu in Python, sowie SQL Alchemy, aber nicht die zugrunde liegende Entwicklung und Datenbank-Konzepte. Ich weiß, was ich tun möchte und wie ich es manuell machen würde, aber ich versuche zu lernen, wie ein ORM funktioniert.Brauchen Sie Hilfe mit Joins in sqlalchemy

Ich habe zwei Tabellen, Bilder und Schlüsselwörter. Die Images-Tabelle enthält eine ID-Spalte, die ihr Primärschlüssel ist, sowie einige andere Metadaten. Die Tabelle Keywords enthält nur eine ID-Spalte (Fremdschlüssel für Bilder) und eine Schlüsselwortspalte. Ich versuche, diese Beziehung richtig zu deklarieren, indem ich die deklarative Syntax verwende, die ich richtig gemacht habe.

Base = declarative_base() 

class Keyword(Base): 
    __tablename__ = 'Keywords' 
    __table_args__ = {'mysql_engine' : 'InnoDB'} 

    id = Column(Integer, ForeignKey('Images.id', ondelete='CASCADE'), 
      primary_key=True) 
    keyword = Column(String(32), primary_key=True) 

class Image(Base): 
    __tablename__ = 'Images' 
    __table_args__ = {'mysql_engine' : 'InnoDB'} 

    id = Column(Integer, primary_key=True, autoincrement=True) 
    name = Column(String(256), nullable=False) 
    keywords = relationship(Keyword, backref='image') 

Dies steht für eine Viele-zu-Viele-Beziehung. Ein Bild kann viele Schlüsselwörter haben und ein Schlüsselwort kann sich auf viele Bilder beziehen.

Ich möchte eine Stichwortsuche meiner Bilder machen. Ich habe das folgende ohne Glück versucht.

Konzeptionell wäre das nett gewesen, aber ich verstehe, warum es nicht funktioniert.

image = session.query(Image).filter(Image.keywords.contains('boy')) 

Ich bekomme immer wieder Fehler über keine Fremdschlüsselbeziehung, was mir klar zu definieren scheint. Ich habe etwas gesehen, um sicherzustellen, dass ich das richtige "Join" bekomme, und ich benutze "von sqlalchemy.orm import join", aber immer noch kein Glück.

image = session.query(Image).select_from(join(Image, Keyword)).\ 
     filter(Keyword.keyword == 'boy') 

Ich fügte die spezifische Join-Klausel der Abfrage hinzu, um es zu helfen, obwohl, wie ich es verstehe, ich dies nicht tun sollte.

image = session.query(Image).select_from(join(Image, Keyword, 
    Image.id==Keyword.id)).filter(Keyword.keyword == 'boy') 

Also endlich wechselte ich die Taktik und versuchte, die Schlüsselwörter abzufragen und dann die Rückreferenz zu verwenden. Wenn ich versuche, die '.images' zu verwenden, die über das Ergebnis iterieren, erhalte ich die Fehlermeldung, dass die Eigenschaft 'image' nicht existiert, obwohl ich sie als backref deklariert habe.

result = session.query(Keyword).filter(Keyword.keyword == 'boy').all() 

Ich möchte in der Lage sein, eine eindeutige Reihe von Bildtreffern auf einer Reihe von Schlüsselwörtern abzufragen. Ich kann einfach nicht meinen Weg zur Syntax erraten, und ich habe Tage damit verbracht, die SQL-Alchemie-Dokumentation zu lesen, die versucht, das selbst herauszufinden.

Ich würde sehr jemanden schätzen, der darauf hinweisen kann, was ich vermisse.

Antwort

1

Es scheint, dass ich immer noch die falsche Version von Join erhielt, sogar den unter sqlalchemy.orm importieren. Ich habe das Problem zu beheben:

from sqlalchemy.orm.util import join as join_ 

image = session.query(Image).select_from(join_(Image, Keyword)).\ 
    filter(Keyword.keyword == 'boy') 

Ist das wirklich die „am weitesten rechts“ Lösung, oder bin ich etwas Nuance von Python fehlt? Da ich noch lerne, würde ich gerne die Dinge so "richtig" machen, wie es von denen mit mehr Erfahrung empfohlen wird. Vielen Dank.

+0

Die 'join_' ist nicht notwendig, da bei der Auswahl einer 'Schlüsselwort'-Entität die zugehörige' Image'-Entität entsprechend der Beziehung, die für das 'image' -Attribut definiert wurde, zusammen mit ihr abgerufen wird. Ich habe es versucht und es funktioniert: '[k.image.name für k in session.query (Keyword) .filter_by (keyword = 'boy'). All()]' – scoffey

+0

Allerdings brauchen Sie * join_', wenn Sie eine 'session.query (Image)' ausführen. Aber in Ihrem Modell ist es einfacher, "Schlüsselwort" -Entitäten abzufragen (die nur ein Bild haben) als "Bild" -Entitäten (die viele Schlüsselwörter haben). Tatsächlich hätten Sie in einer "Viele-zu-Viele-Beziehung" in normaler Form noch eine Schlüsselworttabelle und eine Zwischenbeziehungstabelle mit Fremdschlüsseln zu den Schlüsselwörtern und Bildern.In diesem Fall sind diese beiden Tabellen identisch, da ein Schlüsselwort außer einer Zeichenfolge keine Attribute benötigt. (Also meiner Meinung nach ist es sowieso ein gutes relationales Design.) – scoffey