Ich habe zwei Fläschchen-SQLAlchemy Modelle mit einer einfachen Eins-zu-viele-Beziehung, wie das minimal Beispiel unten:SQLAlchemy: Hybrid-Expression mit Beziehung
class School(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30))
address = db.Column(db.String(30))
class Teacher(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30))
id_school = db.Column(db.Integer, db.ForeignKey(School.id))
school = relationship('School', backref='teachers')
Dann füge ich eine Hybrid-Eigenschaft auf Lehrer, die verwendet Beziehung, wie:
@hybrid_property
def school_name(self):
return self.school.name
Und diese Eigenschaft funktioniert gut, wenn ich es als teacher_instance.school_name
verwenden. Allerdings würde Ich mag auch Anfragen wie Teacher.query.filter(Teacher.school_name == 'x')
machen, aber das gibt mir eine Fehlermeldung:
`AttributeError: Neither 'InstrumentedAttribute' object nor
'Comparator' object has an attribute 'school_name'`.
Nach SQLAlchemy Dokumentation, habe ich einen einfachen Hybrid Ausdruck, wie die folgenden:
@school_name.expression
def school_name(cls):
return School.name
jedoch Wenn ich dieselbe Abfrage erneut ausprobiere, wird eine SQL-Abfrage ohne die Join-Klausel generiert, sodass ich alle verfügbaren Zeilen in der Schule erhalte, nicht nur diejenigen, die mit dem Fremdschlüssel in Teacher übereinstimmen.
Von SQLAlchemy Dokumentation wurde mir klar, dass der Ausdruck einen Zusammenhang erwartet, wo die Verbindung bereits vorhanden ist, so habe ich versucht, die Abfrage erneut als:
Teacher.query.join(School).filter(Teacher.school_name == 'x')
Und das tatsächlich funktioniert, aber es Niederlagen der Zweck der Ich versuche, den syntaktischen Zucker erst dort zu bekommen, wenn ich das Schulmodell kennen muss, um das zu bekommen. Ich nehme an, dass es einen Weg gibt, diesen Ausdruck zu verbinden, aber ich konnte ihn nirgends finden. Die Dokumentation hat ein Beispiel mit dem Ausdruck, der eine Unterabfrage zurückgibt, die direkt mit der select()
erstellt wurde, aber selbst das hat bei mir nicht funktioniert.
Irgendwelche Ideen?
UPDATE
Nach Eevee Antwort unten, ich den Verein Proxy wie vorgeschlagen verwendet und es funktioniert, aber ich habe auch mit der Bemerkung merkwürdig, dass es mit der select()
Unterabfrage arbeiten soll und versucht, herauszufinden, was ich falsch gemacht. Mein ursprünglicher Versuch war:
@school_name.expression
def school_name(cls):
return select(School.name).where(cls.id_school == School.id).as_scalar()
Und es stellt sich heraus, dass gab mir einen Fehler, weil ich die Liste in select() verpasst habe. Der folgende Code funktioniert:
@school_name.expression
def school_name(cls):
return select([School.name]).where(cls.id_school == School.id).as_scalar()
Das ist lächerlich einfach. Danke vielmals. –
Sie hatten Recht mit dem 'select()'. Mein Fehler. Ich habe ein Update zu der Frage hinzugefügt, die es genau beschreibt. –