SqlAlchemy - Filtrando por atributo de relacionamento


93

Não tenho muita experiência com SQLAlchemy e estou com um problema que não consigo resolver. Tentei pesquisar e tentei muitos códigos. Esta é minha classe (reduzida ao código mais significativo):

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)

e gostaria de consultar todos os pacientes, cujo phenoscore da mãe é (por exemplo) == 10

Como disse, tentei muitos códigos, mas não entendi. A solução lógica, a meu ver, seria

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

porque, você pode acessar .mother.phenoscorepara cada elemento durante a saída, mas, este código não faz isso.

Existe a possibilidade (direta) de filtrar por um atributo de um relacionamento (sem escrever a instrução SQL ou uma instrução extra de junção), preciso desse tipo de filtro mais de uma vez.

Mesmo que não haja uma solução fácil, fico feliz em obter todas as respostas.

Respostas:


167

Use método has()de relacionamento (mais legível):

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

ou junte-se (geralmente mais rápido):

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

9
pacientes = Paciente.query.filter (Paciente.mãe.has (Paciente.phenoscore == 10))
usuário1105851

@ user1105851 has()suporta expressão de condição como argumento sem nome e filter_byargumentos de palavra-chave -style. O último parece mais legível para mim.
Denis Otkidach

@DenisOtkidach correto, mas então seria phenoscore = 10. filter_bysó aceita palavras-chave de igualdade (já que está apenas fazendo ** kwargs nelas)
aruisdante 01 de

@aruisdante Você tem razão, foi uma edição errônea da resposta.
Denis Otkidach

4
em vez disso, use qualquer : patient = Patient.query.filter (Patient.mother.any (phenoscore = 10))
Boston Kenne


7

Eu usei com sessões, mas uma forma alternativa de acessar o campo de relacionamento diretamente é

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

Não testei, mas acho que também funcionaria

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


0

Esta é uma resposta mais geral sobre como consultar relacionamentos.

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

Isso permite que você:

parent_obj.some_relationship.filter(ParentClass.some_attr==True).all()
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.