有 3 个表:Account、Role、User。双方Role并User有一个外键account_id,它指向Account。
用户可以具有多个角色,因此roles_users充当之间的二次关系表的表Role和User。
该Account表是我们应用程序的租户表,用于分隔不同的客户。
请注意,所有表(除此之外Account)都具有与account_id. 这样做有几个原因,但我们假设这样做是为了保持一切一致。
现在,如果我有一个简单的次要关系(User.roles- 被注释掉的那个),一切都按预期工作。好吧..它抛出一个合法的警告(尽管我认为它应该是一个错误):
SAWarning: relationship 'User.roles' will copy column role.account_id to column roles_users.account_id, which conflicts with relationship(s): 'User.roles' (copies user.account_id to roles_users.account_id). Consider applying viewonly=True to read-only relationships, or provide a primaryjoin condition marking writable columns with the foreign() annotation.
Run Code Online (Sandbox Code Playgroud)
这就是为什么我创建了第二个关系User.roles——那个没有被注释掉的关系。查询按预期工作,其中有 2 个条件加入和一切。但是,当我尝试在用户上保存一些角色时出现此错误:
sqlalchemy.orm.exc.UnmappedColumnError: Can't execute sync rule for source column 'roles_users.role_id'; mapper 'Mapper|User|user' does not map this column. Try using an explicit `foreign_keys` collection which does not include destination column 'role.id' (or use a viewonly=True relation).
Run Code Online (Sandbox Code Playgroud)
据我了解,SA 无法弄清楚如何保存辅助对象,因为它有一个自定义primaryjoin,secondaryjoin因此它建议使用viewonly=Truewhich 具有在保存模型时忽略角色关系的效果。
问题是如何为用户保存角色而不必手动完成(示例在代码中注释掉了)。在真实的应用程序中,我们有许多次要关系,我们将它们保存在许多地方。将它们全部重写将是非常困难的。
是否有解决方案可以User.roles = some_roles在保留自定义primaryjoin及secondaryjoin以下内容的同时继续使用?
使用 SA 1.1.9 的完整示例:
SAWarning: relationship 'User.roles' will copy column role.account_id to column roles_users.account_id, which conflicts with relationship(s): 'User.roles' (copies user.account_id to roles_users.account_id). Consider applying viewonly=True to read-only relationships, or provide a primaryjoin condition marking writable columns with the foreign() annotation.
Run Code Online (Sandbox Code Playgroud)
注意:切换primaryjoin与secondaryjoin没有帮助。
为了后代的解决方案 - 切换外部包装器并小心主连接和辅助连接:
而不是这个:
roles = relationship(
Role,
secondary=roles_users,
primaryjoin=and_(foreign(Role.id) == roles_users.c.role_id,
Role.account_id == roles_users.c.account_id),
secondaryjoin=and_(foreign(id) == roles_users.c.user_id,
account_id == roles_users.c.account_id))
Run Code Online (Sandbox Code Playgroud)
做这个:
roles = relationship(
Role,
secondary=roles_users,
primaryjoin=and_(id == foreign(roles_users.c.user_id), account_id == foreign(roles_users.c.account_id)),
secondaryjoin=and_(Role.id == foreign(roles_users.c.role_id), Role.account_id == roles_users.c.account_id),
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
551 次 |
| 最近记录: |