149 votes

SqlAlchemy - Filtrage par attribut de relation

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

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)

et j'aimerais interroger tous les patients dont le phénoscore de la mère est (par exemple) == 10

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

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

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

Existe-t-il une possibilité (directe) de filtrer par un attribut d'une relation (sans écrire la déclaration SQL, ou une déclaration de jointure 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.

245voto

Denis Otkidach Points 13111

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

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

ou s'inscrire (généralement plus rapidement) :

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

13voto

Lafada Points 6393

Vous devez interroger la relation avec la jointure

Vous trouverez l'exemple suivant Stratégies d'interrogation autoréférentielles

12voto

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

Patient.where(mother___phenoscore=10)

C'est beaucoup plus court, surtout pour les filtres complexes, par exemple,

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

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

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

8voto

Finch_Powers Points 444

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

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 également

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

6voto

James Points 855

Il s'agit d'une réponse plus générale sur la manière d'interroger les relations.

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

Cela vous permet de :

parent_obj.some_relationship.filter(ParentClass.some_attr==True).all()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X