web-dev-qa-db-fra.com

SqlAlchemy - Filtrage par attribut de relation

Je n'ai pas beaucoup d'expérience avec SQLAlchemy et j'ai un problème que je ne peux pas résoudre. J'ai essayé de chercher et j'ai essayé beaucoup de code. Voici ma classe (réduite au code le plus significatif):

class Patient(Base):
    __table= '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)

et je voudrais interroger tous les patients, dont le phénoscore de la mère est (par exemple) == 10

Comme dit, j'ai essayé beaucoup de code, mais je ne comprends pas. La solution logique, à mes yeux, serait

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

car, vous pouvez accéder à .mother.phenoscore pour chaque élément lors de la sortie mais, ce code ne le fait pas.

Y a-t-il une possibilité (directe) de filtrer par un attribut d'une relation (sans écrire l'instruction SQL, ou une instruction join supplémentaire), j'ai besoin de ce type de filtre plus d'une fois.

Même s'il n'y a pas de solution facile, je suis heureux d'obtenir toutes les réponses.

79
user1105851

Utilisez la méthode has() de la relation (plus lisible):

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

ou rejoindre (généralement plus rapide):

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

Vous devez interroger la relation avec join

Vous obtiendrez l'exemple de ceci Stratégies de requête auto-référentielle

11
Nilesh

Bonne nouvelle pour vous: j'ai récemment créé un package qui vous permet de filtrer/trier avec des chaînes "magiques" comme dans Django , vous pouvez donc maintenant écrire quelque chose comme

Patient.where(mother___phenoscore=10)

C'est beaucoup plus court, en particulier pour les filtres complexes, disons,

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

J'espère que vous apprécierez ce forfait

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

3

Je l'ai utilisé avec des sessions, mais une autre façon d'accéder directement au champ de la relation est

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

Je ne l'ai pas testé, mais je suppose que cela fonctionnerait aussi

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