SqlAlchemy: filtrado por atributo de relación


94

No tengo mucha experiencia con SQLAlchemy y tengo un problema que no puedo resolver. Intenté buscar y probé mucho código. Esta es mi clase (reducida al código más 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)

y me gustaría consultar a todos los pacientes, cuyo fenoscore de la madre es (por ejemplo) == 10

Como dije, probé mucho código, pero no lo entiendo. La solución lógica, en mi opinión, sería

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

porque puede acceder .mother.phenoscorea cada elemento al generar, pero este código no lo hace.

¿Existe una posibilidad (directa) de filtrar por un atributo de una relación (sin escribir la declaración SQL, o una declaración de unión adicional), necesito este tipo de filtro más de una vez.

Incluso si no hay una solución fácil, estoy feliz de obtener todas las respuestas.

Respuestas:


169

Utilice el método has()de relación (más legible):

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

o únete (generalmente más rápido):

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

9
pacientes = Patient.query.filter (Patient.mother.has (Patient.phenoscore == 10))
user1105851

@ user1105851 has()admite tanto la expresión de condición como argumento sin nombre como los argumentos de filter_bypalabra clave -style. La última me parece más legible.
Denis Otkidach

@DenisOtkidach correcto, pero entonces lo sería phenoscore = 10. filter_bysolo toma palabras clave de igualdad (ya que solo les hace ** kwargs)
aruisdante

@aruisdante Tienes razón, fue edición errónea de la respuesta.
Denis Otkidach

4
use any en su lugar: pacientes = Patient.query.filter (Patient.mother.any (phenoscore = 10))
Boston Kenne


7

Lo usé con sesiones, pero una forma alternativa en la que puede acceder al campo de relación directamente es

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

No lo he probado, pero supongo que esto también funcionaría

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


0

Esta es una respuesta más general sobre cómo consultar relaciones.

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

Esto le permite:

parent_obj.some_relationship.filter(ParentClass.some_attr==True).all()
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.