Рассмотрим следующую модель данных SQLAlchemy
:
class Parent:
@declared_attr
def child_A_id(cls):
return Column(ForeignKey(Child.id), nullable=True)
@declared_attr
def child_B_id(cls):
return Column(ForeignKey(Unit.id), nullable=True)
@declared_attr
def child_A(cls):
return relationship(Child, primaryjoin=lambda: cls.child_A_id == Child.id)
@declared_attr
def child_B(cls):
return relationship(Child, primaryjoin=lambda: cls.child_A_id == Child.id)
Я пытаюсь запросить объект child_A
и child_B
, используя следующий запрос:
session.query(Parent.child_A, Parent.child_B).limit(1).all()
который просто возвращает логическое значение вместо объекта (например, [(False, False)]
вместо [{child_A_columns}, {child_B_columns}]
.
Я посмотрел на SQLAlchemy свойства столбца и отношения возвращают логические значения, который решает эту проблему для одного child
, но не могу понять, как применить его в этом случае, когда один Parent
имеет два отношения child
к одной и той же таблице.
Попытки решения:
parent = session.query(Parent).limit(1).all()
parent.child_A
parent.child_B
Работает, но требует SELECT *
, которого я стараюсь избегать.
session.query(Parent.child_A, Parent.child_B).with_entity(Child).limit(1).all()
возвращает только один Child
.
Я согласен с этим; не могли бы вы объяснить, как использовать здесь нетерпеливую загрузку?
вопрос и ответ, на который вы ссылались объясняет, почему запрос приводит к кортежу из двух логических значений, но для запроса обоих дочерних элементов, которые, согласно описанию, происходят из одной и той же таблицы, вам нужен псевдонимы:
child_a = aliased(Child)
child_b = aliased(Child)
session.query(child_a, child_b).\
select_from(Parent).\
join(child_a, Parent.child_A).\
join(child_b, Parent.child_B)
Если вы хотите использовать Query.with_entities()
, вам все равно нужно сначала подготовить соединения:
session.query(Parent).\
join(child_a, Parent.child_A).\
join(child_b, Parent.child_B).\
with_entities(child_a, child_b)
С другой стороны, вы можете загрузить родителей с их детьми одним запросом:
session.query(Parent).\
options(joinedload(Parent.child_A),
joinedload(Parent.child_B))
Вы хотите избежать одновременного запроса
Parent
или хотите загрузить подходящее решение?