请使用别名类帮助我改进/理解查询。考虑一个在两个位置之间移动的示例,如下所述。
class Location(Base):
__tablename__ = 'location'
id = Column(Integer, primary_key = True)
class Movement(Base):
__tablename__ = 'movement'
id = Column(Integer, primary_key = True)
from_id = Column(None, ForeignKey('location.id')
to_id = Column(None, ForeignKey('location.id')
from_location = relationship('Location', foreign_keys = from_id)
to_location = relationship('Location', foreign_keys = to_id)
要在查询中连接三个表,我正在使用sqlalchemy.orm中的aliased()函数:
FromLocation = aliased(Location)
ToLocation = aliased(Location)
r = session.query(Movement, FromLocation, ToLocation).\
join(FromLocation, Movement.from_id == FromLocation.id).\
join(ToLocation, Movement.to_id == ToLocation.id).first()
第一个问题是“使用r
的智能方式是什么?”查询返回一个键控元组,但唯一的键是'Movement',没有像我期望的那样'FromLocation'。我可以用r [1]得到它,但这很容易被打破。
第二个问题是“我的关系是否合适?”我不认为我必须明确指定连接目标。但是如果没有指定目标,我会收到错误:
r = session.query(Movement, FromLocation, ToLocation).\
join(FromLocation).\
join(ToLocation)
InvalidRequestError: Could not find a FROM clause to join from. Tried joining to <AliasedClass at 0x10cfa16d8; Location>, but got: Can't determine join between 'movement' and '%(4512717680 location)s'; tables have more than one foreign key constraint relationship between them. Please specify the 'onclause' of this join explicitly.
是的,我看到了两个外键,但是如何正确映射它们?
答案 0 :(得分:2)
选项-1:要在KeyedTuple
中添加名称,只需为别名添加名称:
FromLocation = aliased(Location, name="From")
ToLocation = aliased(Location, name="To")
# ...
print(r.keys)
# >>>> ['Movement', 'From', 'To']
选项-2:创建一个查询以仅返回Movement
个实例,但预先加载这两个位置。请注意另外join
语法,指定relationship
而不是密钥对。
r = (session.query(Movement)
.join(FromLocation, Movement.from_location)
.join(ToLocation, Movement.to_location)
.options(contains_eager(Movement.from_location, alias=FromLocation))
.options(contains_eager(Movement.to_location, alias=ToLocation))
).first()
print(r)
print(r.from_location)
print(r.to_location)