SqlAlchemy - Memfilter berdasarkan Atribut Relasi

94

Saya tidak punya banyak pengalaman dengan SQLAlchemy dan saya punya masalah, yang tidak bisa saya pecahkan. Saya mencoba mencari dan saya mencoba banyak kode. Ini adalah Kelas saya (dikurangi menjadi kode yang paling signifikan):

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)

dan saya ingin menanyakan semua pasien, yang fenoscore ibunya (misalnya) == 10

Seperti yang diceritakan, saya mencoba banyak kode, tetapi saya tidak mengerti. Solusi logisnya, di mata saya, adalah

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

karena, Anda dapat mengakses .mother.phenoscoresetiap elemen saat mengeluarkan tetapi, kode ini tidak melakukannya.

Apakah ada kemungkinan (langsung) untuk memfilter berdasarkan atribut hubungan (tanpa menulis Pernyataan SQL, atau pernyataan gabungan tambahan), saya memerlukan filter semacam ini lebih dari satu kali.

Meskipun tidak ada solusi yang mudah, saya senang mendapatkan semua jawaban.

pengguna1105851
sumber

Jawaban:

169

Gunakan metode has()hubungan (lebih mudah dibaca):

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

atau bergabung (biasanya lebih cepat):

patients = Patient.query.join(Patient.mother, aliased=True)\
                    .filter_by(phenoscore=10)
Denis Otkidach
sumber
9
pasien = Patient.query.filter (Patient.mother.has (Patient.phenoscore == 10))
pengguna1105851
@ user1105851 has()mendukung kedua ekspresi kondisi sebagai argumen tanpa nama dan filter_byargumen kata kunci -gaya. Nanti tampaknya lebih mudah dibaca oleh saya.
Denis Otkidach
@DenisOtkidach benar, tapi itu akan terjadi phenoscore = 10. filter_byhanya mengambil kata kunci kesetaraan (karena itu hanya melakukan ** kwargs pada mereka)
aruisdante
@aruisdante Anda benar, itu keliru edit jawabannya.
Denis Otkidach
4
gunakan salah satu sebagai gantinya: patient = Patient.query.filter (Patient.mother.any (phenoscore = 10))
Boston Kenne
12

Anda harus menanyakan relasi dengan join

Anda akan mendapatkan contoh dari Strategi Kueri Referensi-Mandiri ini

Nilesh
sumber
1
Tautan tidak ada.
cyberbeast
7

Saya menggunakannya dengan sesi, tetapi cara alternatif di mana Anda dapat mengakses bidang hubungan secara langsung adalah

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

Saya belum mengujinya, tapi saya rasa ini juga akan berhasil

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

Kabar baik untuk Anda: Saya baru-baru ini membuat paket yang memberi Anda pemfilteran / penyortiran dengan string "ajaib" seperti di Django , jadi Anda sekarang dapat menulis sesuatu seperti

Patient.where(mother___phenoscore=10)

Ini jauh lebih singkat, terutama untuk filter yang rumit, misalnya,

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

Semoga Anda menikmati paket ini

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

Alexander Litvinenko
sumber
0

Ini adalah jawaban yang lebih umum tentang cara menanyakan hubungan.

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

Ini memungkinkan Anda untuk:

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