[英]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錯誤,因為a
和b
都與不同表中的相同字段具有外鍵關系(這通常發生在現有數據庫中)。 我嘗試了多種處理此錯誤的方法,包括創建自定義命名函數( name_for_scalar_relationship()
和name_for_collection_relationship()
),但無濟於事。 在SQLAlchemy中,有沒有一種標准的方法來處理這個問題,或者在反射期間禁用反射創建?
最終目標是以自動方式反映數據庫,而不必為當前存在的數百個表編寫自定義名稱映射,但我不知道該怎么做。 任何幫助表示贊賞。
謝謝
當多個外鍵引用同一列時,看起來我們使用automap獲取屬性名稱沖突。
Base.prepare
允許使用參數name_for_scalar_relationship
和name_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_fk
和gmt_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.