python - SQLAlchemy声明性mixin类上的自引用外键关系与declared_attr
问题描述
我有一个 mixin 类,我在 SQLAlchemy 应用程序的开头附近定义了它,然后继承了我使用的几乎所有声明性模型。
class Owned(object):
@declared_attr
def created_by_id(cls):
return Column(Integer, ForeignKey("accounts.id"),
nullable = True)
@declared_attr
def created_by(cls):
return relationship("Account", foreign_keys = cls.created_by_id)
@declared_attr
def updated_by_id(cls):
return Column(Integer, ForeignKey("accounts.id"),
nullable = True)
@declared_attr
def updated_by(cls):
return relationship("Account", foreign_keys = cls.updated_by_id)
这适用于大多数预期的用例。
class Thing(Owned, Base): # Base is from SQLAlchemy's declarative_base()
pass
account = session.query(Account).first()
thing = Thing(created_by = account, updated_by = account)
session.add(thing)
session.commit()
session.refresh(thing)
assert thing.created_by == account # pass
assert thing.updated_by == account # pass
但是,当我将Account
自己定义为继承自Owned
.
class Account(Owned, Base):
pass
account_old = session.query(Account).first()
account_new = Account(created_by = account_old, updated_by = account_old)
session.add(account_new)
session.commit()
session.refresh(account_new)
assert account_new.created_by_id == account_old.id # pass
assert account_new.updated_by_id == account_old.id # pass
# BUT!
assert account_new.created_by == account_old # fail
assert account_new.updated_by == account_old # fail
account_new.created_by # []
account_new.updated_by # []
我看到,在这种情况下,我已经变成created_by_id
了updated_by_id
自引用外键。然而,我不明白为什么 SQLAlchemy 没有用预期的实例填充它们的关联relationship
列。Account
我究竟做错了什么?
解决方案
在邻接列表关系中,“方向”默认为一对多。使用该remote_side
指令确定关系是多对一的,这就是您所追求的:
def _create_relationship(cls, foreign_keys):
kwgs = {}
# Bit of a chicken or egg situation:
if cls.__name__ == "Account":
kwgs["remote_side"] = [cls.id]
return relationship("Account", foreign_keys=foreign_keys, **kwgs)
class Owned:
@declared_attr
def created_by_id(cls):
return Column(Integer, ForeignKey("accounts.id"),
nullable = True)
@declared_attr
def created_by(cls):
return _create_relationship(cls, cls.created_by_id)
@declared_attr
def updated_by_id(cls):
return Column(Integer, ForeignKey("accounts.id"),
nullable = True)
@declared_attr
def updated_by(cls):
return _create_relationship(cls, cls.updated_by_id)
推荐阅读
- apache - .htaccess 没有被使用 XAMPP 读取
- scrape - axesso.de REST API 不提供基于颜色选择的价格,尺寸(如变体)
- c# - SslStream.AuthenticateAsClient 或 SslStream.AuthenticateAsServer 错误:从传输流接收到意外的 EOF 或 0 字节
- javascript - 从列表中获取缺失序列的函数
- python-3.x - 如何在 np.where 中更改 dtype 和应用数学计算?
- swift - 如何使用 Swift 代码 (macOS) 发送电子邮件背景
- laravel - Laravel 依赖注入和参数传递在作业分派时工作是同步的,而在延迟时不工作
- typescript - 如何从描述它的模式创建类型?
- excel - 复制、删除重复项、粘贴 V
- sql-server - ASP.NET Core 5 搜索类别和子类别的最快方法