tutorial query espaƱol create python orm sqlalchemy filtering one-to-many

python - query - Filtrar el atributo de uno a varios del objeto de resultado de consulta SQLAlchemy



sqlalchemy select (2)

Digamos que tengo un par de objetos, tengo una relación uno a muchos, algo así como

class Parent(): //id, other cols, etc children = relationship("Child", backref="parent") class Child(): parent_id = Column(Integer, ForeignKey("parent.id") child_type = Column(Enum("a","b"))

Ahora, quiero consultar objetos Parent, pero he filtrado sus hijos por child_type, es decir, algo así como

session.query(Parent).join(Parent.children).filter(Child.child_type == "a")

Esto simplemente devuelve el elemento primario con todos los elementos secundarios, básicamente sin tener en cuenta el filtro. ¿Este resultado es posible o debo consultar también a Child?


Intenta obtener dos respuestas en una consulta. O puede preguntar por todos los padres que tienen un tipo de niño o puede pedir todo tipo de niños. En el primer caso, debe filtrar los hijos nuevamente, si desea los hijos correspondientes, en el segundo caso puede obtener los padres correspondientes de manera simple. Pero de qué manera es la correcta, depende del problema adicional, tratas de resolver.


De hecho, su consulta agrega un join y un filtro, pero solo devuelve instancias Parent . De hecho, solo las instancias principales que tienen al menos un Child de tipo a .
Cuando accede a .children en cada uno de esos padres, se emitirá una nueva instrucción SQL y se cargarán todos los hijos de ese padre. Puede volver a aplicar el filtro en la memoria, o crear su propia consulta y no confiar en la navegación de relación (comentada) como se muestra a continuación:

# select *only* those parents who have at least one child of type "a" parents = session.query(Parent).join(Parent.children).filter(Child.child_type == "a") for p in parents: # 1. in-memory filter: now select only type "a" children for each parent children_a = [c for c in p.children if c.child_type == ''a''] # 2. custom query: now select only type "a" children for each parent # children_a = session.query(Child).with_parent(p).filter(Child.child_type == "a") print("AAA", p) for c in children_a: print("AAA ..", c)

A continuación, se muestra una forma de hacerlo en una consulta, pero tenga cuidado ya que efectivamente le está diciendo a sqlalchemy que ha cargado a todos los niños para padres. Puede utilizar este enfoque para los escenarios donde realiza su consulta y luego descartar / reciclar la sesión:

# select all parents, and eager-load children of type "a" parents = (session.query(Parent) .join(Parent.children).filter(Child.child_type == "a") # make SA think we loaded all *parent.children* collection .options(contains_eager(''children'')) ) for p in parents: children_a = p.children # now *children* are *incorrectly* filtered print("BBB", p) for c in children_a: print("BBB ..", c)