SqlAlchemy - 按关系属性过滤

use*_*851 85 python sqlalchemy foreign-keys filter

我对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)
Run Code Online (Sandbox Code Playgroud)

我想询问所有患者,其母亲的现象是(例如) == 10

据说,我尝试了很多代码,但我没有得到它.在我看来,逻辑上的解决方案就是

patients = Patient.query.filter(Patient.mother.phenoscore == 10)
Run Code Online (Sandbox Code Playgroud)

因为,您可以.mother.phenoscore在输出时访问每个元素但是,此代码不会这样做.

有没有(直接)过关系属性过滤的可能性(没有编写SQL语句或额外的连接语句),我需要这种过滤器不止一次.

即使没有简单的解决方案,我也很乐意得到所有答案.

Den*_*ach 140

使用has()关系方法(更易读):

patients = Patient.query.filter(Patient.mother.has(phenoscore=10))
Run Code Online (Sandbox Code Playgroud)

或加入(通常更快):

patients = Patient.query.join(Patient.mother, aliased=True)\
                    .filter_by(phenoscore=10)
Run Code Online (Sandbox Code Playgroud)

  • 使用 **any** 代替:病人 = Patient.query.filter(Patient.mother.any(phenoscore=10)) (7认同)
  • 患者= Patient.query.filter(Patient.mother.has(Patient.phenoscore == 10)) (5认同)

Nil*_*esh 11

您必须使用join查询relationsip

您将从此自引用查询策略中获取示例


小智 8

对你来说好消息:我最近制作了一个包,可以让你像 Django 一样使用“神奇”字符串进行过滤/排序,所以你现在可以编写类似的东西

Patient.where(mother___phenoscore=10)
Run Code Online (Sandbox Code Playgroud)

它要短得多,特别是对于复杂的过滤器,例如,

Comment.where(post___public=True, post___user___name__like='Bi%')
Run Code Online (Sandbox Code Playgroud)

希望您会喜欢这个套餐

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


Fin*_*ers 8

I used it with sessions, but an alternate way where you can access the relationship field directly is

db_session.query(Patient).join(Patient.mother) \
    .filter(Patient.mother.property.mapper.class_.phenoscore==10)
Run Code Online (Sandbox Code Playgroud)

I have not tested it, but I guess this would also work

Patient.query.join(Patient.mother) \
    .filter(Patient.mother.property.mapper.class_.phenoscore==10)
Run Code Online (Sandbox Code Playgroud)


Jam*_*mes 6

这是关于如何查询关系的更一般的答案。

relationship(..., lazy='dynamic', ...)
Run Code Online (Sandbox Code Playgroud)

这使您能够:

parent_obj.some_relationship.filter(ParentClass.some_attr==True).all()
Run Code Online (Sandbox Code Playgroud)


Yaa*_*ler 5

对于那些希望使用声明性基础来完成此过滤器的人,您可以使用关联代理

from sqlalchemy.ext.associationproxy import association_proxy

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)

    """
    Access the associated object(s) through this proxy
    
    Note: Because the above relationship doesn't use a
      collection (uselist=False), the associated attribute
      will be a scalar. If the relationship does use a
      collection (uselist=True), the associated attribute 
      would then be a list (or other defined collection) of values.
    """
    mother_phenoscore = association_proxy('mother', 'phenoscore')
Run Code Online (Sandbox Code Playgroud)

您可以直接查询子项,而不是has()在关系上使用:

patients = Patient.query.filter(Patient.mother_phenoscore == 10)
Run Code Online (Sandbox Code Playgroud)