簡體   English   中英

Python/SqlAlchemy 將表連接到自身不生成預期的查詢

[英]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的參數:

sqlalchemy.orm.relationship.params.join_depth

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM