![](/img/trans.png)
[英]SQLAlchemy Joining a Session into an External Transaction Not Working as Expected
[英]Python/SqlAlchemy joining table to itself not generating expected query
我想做的事情似乎应该很简单。 我想将代表数据收集站的表连接到自身,以便跟踪部署在同一位置的站的先前迭代。
在下面的代码中,我有两个类:StationTable 和 StationTypeTable。 StationTable 有两个 FK 关系——一个到站类型,另一个回到站表。
最后是生成的 SQL,它显示了对 StationType 表的正确连接,但没有任何痕迹由 previous_station 列创建的链接。
我究竟做错了什么? 请注意,这最终将与 FastApi 和 Async Postgres 驱动程序一起使用,这可能会或可能不会引起人们的兴趣。 另外,我不需要通过关系修改相关表; 我只需要读取一些属性。
使用 SQLAlchemy 1.4,最新版本。
from typing import Any
import sqlalchemy as sa
from sqlalchemy import select
from sqlalchemy.orm import registry, RelationshipProperty
from sqlalchemy.schema import ForeignKey
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm.decl_api import DeclarativeMeta
mapper_registry = registry()
class BaseTable(metaclass=DeclarativeMeta):
__abstract__ = True
registry = mapper_registry
metadata = mapper_registry.metadata
__init__ = mapper_registry.constructor
id = sa.Column(UUID(as_uuid=True), primary_key=True, server_default=sa.text("gen_random_uuid()"))
class Relationship(RelationshipProperty): # type: ignore
""" Using this class hides some of the static typing messiness in SQLAlchemy. """
inherit_cache = True # If this works, should improve performance
def __init__(self, *args: Any, **kwargs: Any):
if "lazy" not in kwargs:
# 'joined' means items should be loaded "eagerly" in the same query as that of the parent, using a JOIN or LEFT
# OUTER JOIN. Whether the join is "outer" or not is determined by the relationship.innerjoin parameter.
# We need this to keep loading in async mode from blowing up.
# https://docs.sqlalchemy.org/en/14/orm/relationship_api.html
kwargs["lazy"] = "joined"
super().__init__(*args, **kwargs)
class StationTypeTable(BaseTable):
__tablename__ = "station_type"
name = sa.Column(sa.String(255), unique=True, nullable=False)
description = sa.Column(sa.UnicodeText)
class StationTable(BaseTable):
__tablename__ = "station"
name = sa.Column(sa.String(255), unique=True, nullable=False)
installation_date = sa.Column(sa.BigInteger, nullable=False)
station_type_id = sa.Column(UUID(as_uuid=True), ForeignKey(StationTypeTable.id), nullable=False)
previous_station = sa.Column(UUID(as_uuid=True), ForeignKey("station.id"), nullable=True)
station_type_table = Relationship(StationTypeTable, uselist=False)
previous_station_table = Relationship("StationTable", uselist=False) # self join, uselist=False ==> one-to-one
query = select(StationTable)
print(query)
# SELECT station.id, station.name, station.installation_date, station.station_type_id, station.previous_station,
# station_type_1.id AS id_1, station_type_1.name AS name_1, station_type_1.description
# FROM station
# LEFT OUTER JOIN station_type AS station_type_1 ON station_type_1.id = station.station_type_id
编辑:
根据下面 Ian Wilson 的回复,我将参数join_depth=1
添加到 previous_station_table 关系,这确实为关系生成了 SQL,但奇怪的是,与 station_type_table 关系相比,它是“错误的方式”。 这是使用该参数生成的 SQL:
SELECT station.id, station.name, station.installation_date,
station.station_type_id, station.previous_station,
station_type_1.id AS id_1, station_type_1.name AS name_1,
station_type_1.description, station_type_2.id AS id_2,
station_type_2.name AS name_2, station_type_2.description AS description_1,
station_1.id AS id_3, station_1.name AS name_3,
station_1.installation_date AS installation_date_1,
station_1.station_type_id AS station_type_id_1,
station_1.previous_station AS previous_station_1
FROM station
LEFT OUTER JOIN station_type AS station_type_1
ON station_type_1.id = station.station_type_id -- looks right
LEFT OUTER JOIN station AS station_1
ON station.id = station_1.previous_station -- looks backward, see below
LEFT OUTER JOIN station_type AS station_type_2
ON station_type_2.id = station_1.station_type_id
我认为标记的行应该是:
LEFT OUTER JOIN station AS station_1 ON station.previous_station = station_1.id
问题似乎是您必须为自引用预加载设置join_depth
,我将其设置为join_depth=1
并且这似乎修复了查询。 由于您有一个额外的急切加入,这实际上会创建 3 个加入而不是 2 个加入,因为第二组站也必须加入类型。 该文档在此处解释了join_depth
:
这里简要解释了relatoinship
的参数:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.