SqlAlchemy - กรองตามคุณสมบัติความสัมพันธ์


98

ฉันไม่มีประสบการณ์กับ 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 หรือคำสั่งเข้าร่วมเพิ่มเติม) ฉันต้องการตัวกรองประเภทนี้มากกว่าหนึ่งครั้ง

ถึงแม้จะไม่มีวิธีง่ายๆ แต่ก็ยินดีรับคำตอบทุกประการ

คำตอบ:


176

ใช้วิธีการhas()สร้างความสัมพันธ์ (อ่านเพิ่มเติม):

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

หรือเข้าร่วม (โดยปกติจะเร็วกว่า):

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

9
ผู้ป่วย = Patient.query.filter (Patient.mother.has (Patient.phenoscore == 10))
user1105851

@ user1105851 has()สนับสนุนทั้งการแสดงออกสภาพเป็นอาร์กิวเมนต์ชื่อและfilter_byข้อโต้แย้งคำหลักสไตล์ ในภายหลังดูเหมือนว่าฉันอ่านได้มากขึ้น
Denis Otkidach

@DenisOtkidach ถูกต้อง แต่แล้วมันจะเป็นphenoscore = 10อย่างไร filter_byใช้คำหลักที่เท่าเทียมกันเท่านั้น (เนื่องจากมันทำ ** kwargs กับพวกเขา)
aruisdante

@aruisdante คุณพูดถูกมันเป็นการแก้ไขคำตอบที่ผิดพลาด
Denis Otkidach

5
ใช้อย่างใดอย่างหนึ่งแทน: ผู้ป่วย = Patient.query.filter (Patient.mother.any (phenoscore = 10))
Boston Kenne


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


1

นี่คือคำตอบทั่วไปเกี่ยวกับวิธีสอบถามความสัมพันธ์

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

สิ่งนี้ช่วยให้คุณ:

parent_obj.some_relationship.filter(ParentClass.some_attr==True).all()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.