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.

user1105851
quelle

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)
Denis Otkidach
quelle
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
12

Sie müssen die Beziehung mit join abfragen

Sie erhalten das Beispiel aus diesen selbstreferenziellen Abfragestrategien

Nilesh
quelle
1
Link existiert nicht.
Cyberbeast
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)
Finch_Powers
quelle
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

Alexander Litvinenko
quelle
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()
James
quelle