SqlAlchemy - Фільтрування за атрибутом відносин


94

У мене немає великого досвіду роботи з SQLAlchemy, і у мене є проблема, яку я не можу вирішити. Я спробував здійснити пошук і спробував багато коду. Це мій клас (зведений до найважливішого коду):

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)

і я хотів би запитати всіх пацієнтів, у яких феноскор матері (наприклад) == 10

Як сказано, я спробував багато коду, але не отримую його. На мої очі, логічне рішення було б

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

тому що ви можете отримати доступ .mother.phenoscoreдо кожного елемента під час виведення, але цей код цього не робить.

Чи існує (пряма) можливість фільтрувати за атрибутом відносини (без написання заяви SQL або додаткового оператора join), мені потрібен такий фільтр більше одного разу.

Навіть якщо простого рішення немає, я радий отримати всі відповіді.

Відповіді:


169

Використовуйте метод has()відносин (більш читабельний):

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

або приєднатися (зазвичай швидше):

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

9
Patients = Patient.query.filter (Patient.mother.has (Patient.phenoscore == 10))
1105851

@ user1105851 has()підтримує як вираз умови як неназваний аргумент, так і filter_byаргументи ключового слова -style . Пізніше мені здається більш читабельним.
Денис Откідач

@DenisOtkidach правильно, але тоді це буде phenoscore = 10. filter_byприймає лише ключові слова рівності (оскільки це просто робить ** кварги на них)
aruisdante

@aruisdante Ви маєте рацію, це було помилковим редагуванням відповіді.
Денис Откідач,

4
замість цього використовувати будь-який : пацієнти = Patient.query.filter (Patient.mother.any (phenoscore = 10))
Бостон,


7

Я використовував його під час сеансів, але альтернативним способом прямого доступу до поля відносин є

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

Я його не тестував, але, мабуть, це також спрацює

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

5

Хороші новини для вас: нещодавно я зробив пакет, який дає вам можливість фільтрувати / сортувати за "чарівними" рядками, як у Django , так що тепер ви можете написати щось на зразок

Patient.where(mother___phenoscore=10)

Це набагато коротше, особливо для складних фільтрів, скажімо,

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

Сподіваюся, вам сподобається цей пакет

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


0

Це більш загальна відповідь про те, як запитувати стосунки.

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

Це дозволяє:

parent_obj.some_relationship.filter(ParentClass.some_attr==True).all()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.