SqlAlchemy - Filtern nach Beziehungsattribut


93

Ich habe nicht viel Erfahrung mit SQLAlchemy und ich habe ein Problem, das ich nicht lösen kann. Ich habe versucht zu suchen und ich habe viel Code ausprobiert. Dies ist meine Klasse (reduziert auf den wichtigsten Code):

class Patient(Base):
    __tablename__ = 'patients'
    id = Column(Integer, primary_key=True, nullable=False)
    mother_id = Column(Integer, ForeignKey('patients.id'), index=True)
    mother = relationship('Patient', primaryjoin='Patient.id==Patient.mother_id', remote_side='Patient.id', uselist=False)
    phenoscore = Column(Float)

und ich möchte alle Patienten befragen, deren Phenoscore der Mutter ist (zum Beispiel) == 10

Wie gesagt, ich habe viel Code ausprobiert, aber ich verstehe ihn nicht. Die logische Lösung wäre in meinen Augen

patients = Patient.query.filter(Patient.mother.phenoscore == 10)

Sie können .mother.phenoscorebei der Ausgabe auf jedes Element zugreifen , dieser Code tut dies jedoch nicht.

Gibt es eine (direkte) Möglichkeit, nach einem Attribut einer Beziehung zu filtern (ohne die SQL-Anweisung oder eine zusätzliche Join-Anweisung zu schreiben), benötige ich diese Art von Filter mehr als einmal.

Auch wenn es keine einfache Lösung gibt, freue ich mich über alle Antworten.

Antworten:


166

Verwenden Sie die has()Beziehungsmethode (besser lesbar):

patients = Patient.query.filter(Patient.mother.has(phenoscore=10))

oder beitreten (normalerweise schneller):

patients = Patient.query.join(Patient.mother, aliased=True)\
                    .filter_by(phenoscore=10)

9
patient = Patient.query.filter (Patient.mother.has (Patient.phenoscore == 10))
user1105851

@ user1105851 has()unterstützt sowohl Bedingungsausdrücke als unbenanntes Argument als auch filter_by-style-Schlüsselwortargumente. Letzteres erscheint mir lesbarer.
Denis Otkidach

@DenisOtkidach richtig, aber dann wäre es phenoscore = 10. filter_bynimmt nur Gleichheitsschlüsselwörter (da es nur ** kwargs auf ihnen macht)
aruisdante

@aruisdante Du hast recht, es war eine fehlerhafte Bearbeitung der Antwort.
Denis Otkidach

4
Verwenden Sie stattdessen any : patient = Patient.query.filter (Patient.mother.any (Phenoscore = 10))
Boston Kenne


7

Ich habe es für Sitzungen verwendet, aber eine alternative Möglichkeit, direkt auf das Beziehungsfeld zuzugreifen, ist

db_session.query(Patient).join(Patient.mother) \
    .filter(Patient.mother.property.mapper.class_.phenoscore==10)

Ich habe es nicht getestet, aber ich denke, das würde auch funktionieren

Patient.query.join(Patient.mother) \
    .filter(Patient.mother.property.mapper.class_.phenoscore==10)

5

Gute Nachrichten für Sie: Ich habe kürzlich ein Paket erstellt, mit dem Sie wie in Django mit "magischen" Zeichenfolgen filtern / sortieren können, sodass Sie jetzt so etwas wie schreiben können

Patient.where(mother___phenoscore=10)

Es ist viel kürzer, insbesondere für komplexe Filter, z.

Comment.where(post___public=True, post___user___name__like='Bi%')

Ich hoffe, Sie werden dieses Paket genießen

https://github.com/absent1706/sqlalchemy-mixins#django-like-queries


0

Dies ist eine allgemeinere Antwort zum Abfragen von Beziehungen.

relationship(..., lazy='dynamic', ...)

Dies ermöglicht Ihnen:

parent_obj.some_relationship.filter(ParentClass.some_attr==True).all()
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.