SQLAlchemy: Hybridausdruck mit Beziehung

Ich habe zwei Flask-SQLAlchemy-Modelle mit einer einfachen Eins-zu-Viele-Beziehung, wie im folgenden minimalen Beispiel:

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 dem Lehrer eine hybride Eigenschaft hinzu, die die Beziehung verwendet, wie:

@hybrid_property
def school_name(self):
    return self.school.name

Und diese Eigenschaft funktioniert einwandfrei, wenn ich sie als verwendeteacher_instance.school_name. Ich möchte aber auch gerne Rückfragen stellenTeacher.query.filter(Teacher.school_name == 'x'), aber das gibt mir einen Fehler:

`AttributeError: Neither 'InstrumentedAttribute' object nor 
'Comparator' object has an attribute 'school_name'`. 

Nach der SQLAlchemy-Dokumentation habe ich einen einfachen hybriden Ausdruck wie den folgenden hinzugefügt:

@school_name.expression
def school_name(cls):
    return School.name

Wenn ich dieselbe Abfrage jedoch erneut versuche, wird eine SQL-Abfrage ohne die Join-Klausel generiert, sodass alle verfügbaren Zeilen in School abgerufen werden, nicht nur die, die dem Fremdschlüssel in Teacher entsprechen.

In der SQLAlchemy-Dokumentation wurde mir klar, dass der Ausdruck einen Kontext erwartet, in dem der Join bereits vorhanden ist. Daher habe ich die Abfrage wie folgt wiederholt:

Teacher.query.join(School).filter(Teacher.school_name == 'x')

Und das funktioniert tatsächlich, aber es macht den Versuch zunichte, den syntaktischen Zucker dort reinzuholen, wenn ich Kenntnisse des Schulmodells benötige, um dies zu erreichen. Ich gehe davon aus, dass es eine Möglichkeit gibt, diesen Join in den Ausdruck aufzunehmen, aber ich konnte ihn nirgendwo finden. Die Dokumentation enthält ein Beispiel mit dem Ausdruck, der eine Unterabfrage zurückgibt, die direkt mit dem Befehl erstellt wurdeselect(), aber auch das hat bei mir nicht geklappt.

Irgendwelche Ideen?

AKTUALISIEREN

Nach der Antwort von Eevee unten habe ich den Assoziations-Proxy wie vorgeschlagen verwendet und es funktioniert, aber ich wurde auch neugierig mit dem Kommentar, dass es mit dem funktionieren sollteselect() Unterabfrage und versuchte herauszufinden, was ich falsch gemacht habe. 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 stellte sich heraus, dass mir ein Fehler unterlaufen ist, weil ich die Liste in select () verpasst habe. Der folgende Code funktioniert gut:

@school_name.expression
def school_name(cls):
    return select([School.name]).where(cls.id_school == School.id).as_scalar()

Antworten auf die Frage(1)

Ihre Antwort auf die Frage