簡體   English   中英

SQLAlchemy Automap backref錯誤

[英]SQLAlchemy Automap backref errors

我是SQLAlchemy的新手(通常是ORM),我正在嘗試將現有的應用程序移到SQLAlchemy上,以便我們可以將一些代碼復雜性從當前存在的(和繁瑣的更新)查詢轉移到Python。 不幸的是,我在數據庫反射后立即收到錯誤。 雖然我可以直接查詢表,但我實際上並沒有直接訪問類或類之間的關系。 下面是我想要做的幾乎最小的例子。

現有的postgres表:

dev=> \d+ gmt_file
                                        Table "public.gmt_file"
  Column   |     Type     | Modifiers | Storage  | Stats target | Description 
-----------+--------------+-----------+----------+--------------+-------------
 file_id   | integer      | not null  | plain    |              |
       a   | integer      |           | plain    |              | 
       b   | integer      |           | plain    |              | 
Indexes:
    "gmt_file_pk" PRIMARY KEY, btree (file_id)
Foreign-key constraints:
    "gmt_file_a_fk" FOREIGN KEY (a) REFERENCES cmn_user(user_id)
    "gmt_file_b_fk" FOREIGN KEY (b) REFERENCES cmn_user(user_id)

SQLAlchemy應用程序(最小示例):

from sqlalchemy import create_engine
from sqlalchemy.orm import Session,Mapper
from sqlalchemy.ext.automap import automap_base

engine = create_engine('postgresql://user:pass@localhost:5432/dev')
Base = automap_base()
Base.prepare(engine, reflect=True)
session = Session(engine,autocommit=True)

session.query(Base.classes.gmt_file).all()

從目前為止我所知道的,這會引發backref錯誤,因為ab都與不同表中的相同字段具有外鍵關系(這通常發生在現有數據庫中)。 我嘗試了多種處理此錯誤的方法,包括創建自定義命名函數( name_for_scalar_relationship()name_for_collection_relationship() ),但無濟於事。 在SQLAlchemy中,有沒有一種標准的方法來處理這個問題,或者在反射期間禁用反射創建?

最終目標是以自動方式反映數據庫,而不必為當前存在的數百個表編寫自定義名稱映射,但我不知道該怎么做。 任何幫助表示贊賞。

謝謝

當多個外鍵引用同一列時,看起來我們使用automap獲取屬性名稱沖突。

Base.prepare允許使用參數name_for_scalar_relationshipname_for_collection_relationship ,它們使用用於生成屬性名稱的函數。 (參見AutomapBase.prepare()name_for_collection_relationship()文檔)我能夠通過定義自己的函數來解決backref錯誤。

修改你的最小例子:

from sqlalchemy import create_engine
from sqlalchemy.orm import Session,Mapper
from sqlalchemy.ext.automap import automap_base, name_for_collection_relationship

engine = create_engine('postgresql://user:pass@localhost:5432/dev')
Base = automap_base()

def _name_for_collection_relationship(base, local_cls, referred_cls, constraint):
    if constraint.name:
        return constraint.name.lower()
    # if this didn't work, revert to the default behavior
    return name_for_collection_relationship(base, local_cls, referred_cls, constraint)

Base.prepare(engine, reflect=True, name_for_collection_relationship=_name_for_collection_relationship)
session = Session(engine,autocommit=True)

session.query(Base.classes.gmt_file).all()

這應該有一個屬性名為gmt_file_a_fkgmt_file_b_fk

這種方法對我有用。 如果它不起作用,您也可以嘗試類似地重新定義name_for_scalar_relationship()

如果要根據類重寫,則必須確保正確定義列和關系。 例如:

from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.orm import relationship

class GmtFile(Base):
    __tablename___ = 'gmt_file'

    file_id = Column('file_id', Integer, primary_key=True)

    a = Column('a', Integer, ForeignKey('CmnUser.user_id', name='gmt_file_a'))
    b = Column('b', Integer, ForeignKey('CmnUser.user_id', name='gmt_file_b'))
    # you'll need to define the class CmnUser as well

    # these variable names need to be the same as the ForeignKey names above
    gmt_file_a = relationship('CmnUser', foreign_keys=[a])
    gmt_file_b = relationship('CmnUser', foreign_keys=[b])

暫無
暫無

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

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