SqlAlchemy - Filtro per attributo di relazione


93

Non ho molta esperienza con SQLAlchemy e ho un problema che non riesco a risolvere. Ho provato a cercare e ho provato molto codice. Questa è la mia classe (ridotta al codice più significativo):

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)

e vorrei interrogare tutti i pazienti, la cui madre è fenoscore (per esempio) == 10

Come detto, ho provato molto codice, ma non l'ho capito. La soluzione logica, ai miei occhi, sarebbe

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

perché puoi accedere .mother.phenoscoreper ogni elemento durante l'output ma questo codice non lo fa.

Esiste una possibilità (diretta) di filtrare in base a un attributo di una relazione (senza scrivere l'istruzione SQL o un'istruzione di join aggiuntiva), ho bisogno di questo tipo di filtro più di una volta.

Anche se non esiste una soluzione semplice, sono felice di ricevere tutte le risposte.

Risposte:


167

Usa metodo has()di relazione (più leggibile):

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

o unisciti (di solito più velocemente):

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

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

@ user1105851 has()supporta sia l'espressione di condizione come argomento senza nome sia come argomenti di filter_byparole chiave in stile. Il secondo mi sembra più leggibile.
Denis Otkidach

@DenisOtkidach corretto, ma allora sarebbe phenoscore = 10. filter_byaccetta solo parole chiave di uguaglianza (dal momento che sta solo facendo ** kwarg su di esse)
aruisdante

@aruisdante Hai ragione, è stata una modifica errata della risposta.
Denis Otkidach

4
usa qualsiasi : pazienti = Patient.query.filter (Patient.mother.any (phenoscore = 10))
Boston Kenne


7

L'ho usato con le sessioni, ma un modo alternativo in cui puoi accedere direttamente al campo della relazione è

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

Non l'ho testato, ma credo che funzionerebbe anche questo

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


0

Questa è una risposta più generale su come interrogare le relazioni.

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

Questo ti permette di:

parent_obj.some_relationship.filter(ParentClass.some_attr==True).all()
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.