python - 不同属性上的双向外键,一对一和一对多
问题描述
我有两个模型:User
和ReferralKey
,有这些要求:
- 在创建 时
User
,ReferralKey
会自动创建 a 并将其添加到数据库中 ReferralKey
跟踪它推荐了哪些用户ReferralKey
跟踪哪个用户拥有它
根据这个问题的答案,最好的解决方案似乎是ReferralKey
在User
. 其他两个的解决方案需要外键,而且看起来真的很乱——把表纠缠在一起,我还不如把它们放在同一个表中。
第一个的解决方案如下所示:
def User(model):
id = Column(BigInteger(), autoincrement=True, primary_key=True)
referral_key = relationship('ReferralKey', uselist=False)
...
def __init__(self):
self.referral_key = ReferralKey()
def ReferralKey(model):
id = Column(BigInteger(), autoincrement=True, primary_key=True)
user_id = Column(BigInteger(), ForeignKey('user.id', ondelete='SET NULL'), nullable=True)
这按预期工作,并解决了第一点和第三点。尝试解决第二个问题时会出现问题。这(出于某种原因)需要一个新的外键 in User
,这需要relationship
在两者中声明 aUser
并且ReferralKey
(我猜)消除外键的歧义:
def User(model):
id = Column(BigInteger(), autoincrement=True, primary_key=True)
referral_key = relationship('ReferralKey', uselist=False)
referrer_id = Column(BigInteger(), ForeignKey('referral_key.id', ondelete='SET NULL'))
referrer = relationship('ReferralKey', foreign_keys=['referrer_id'], backref='used_by')
...
def __init__(self):
self.referral_key = ReferralKey()
def ReferralKey(model):
__tablename__='referral_key'
id = Column(BigInteger(), autoincrement=True, primary_key=True)
user_id = Column(BigInteger(), ForeignKey('user.id', ondelete='SET NULL'), nullable=True)
user = relationship('User', foreign_keys=['user_id'])
relationship
我已经尝试了and的所有不同排列ForeignKey
,并且总是得到相同的错误:
sqlalchemy.exc.CircularDependencyError: Can't sort tables for DROP; an unresolvable foreign key dependency exists between tables: referral_key, users. Please ensure that the ForeignKey and ForeignKeyConstraint objects involved in the cycle have names so that they can be dropped using DROP CONSTRAINT.
最终,我的问题是我只是不明白我在做什么。为什么我需要改变User
桌子才能跟踪桌子上的东西ReferralKey
?声明的目的是什么relationship
——为什么没有这个声明会模棱两可?如果User
有一个外键引用ReferralKey
并且ReferralKey
有一个外键引用——并且在删除的情况下User
应该设置其中任何一个NULL
,为什么 SQL 需要比这更多的信息?
为什么我不能拥有:
def User(model):
id = Column(BigInteger(), autoincrement=True, primary_key=True)
def __init__(self):
ReferralKey(user_id=self.id)
def ReferralKey(model):
__tablename__='referral_key'
id = Column(BigInteger(), autoincrement=True, primary_key=True)
user_id = Column(BigInteger(), ForeignKey('user.id', ondelete='SET NULL'), nullable=True)
used_by = [list of user IDs]
def __init__(self, user_id):
if user_id:
self.user_id == user_id
这对我来说感觉更干净、更直观。如果我想添加(或删除!)推荐密钥,我几乎不必担心添加东西,User
因为它主要独立于推荐密钥的功能。为什么我需要在user
表中添加一列来跟踪我想要ReferralKey
跟踪的内容?
基本上,我完全不知道这一点。有人介意帮助我吗?
解决方案
试试下面的。
它依赖于以下信息:
- 用户在注册时创建自己的主密钥。
- 用户在注册时可以注册从属密钥,但可能不会。
这样外键保留在一个表中,但您需要区分它们..
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
Base= declarative_base()
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
own_referral_id = Column(Integer, ForeignKey('referral_key.id'))
own_referral_key = relationship('ReferralKey', foreign_keys=[own_referral_id], back_populates='owner')
signup_referral_id = Column(Integer, ForeignKey('referral_key.id'))
signup_referral_key = relationship('ReferralKey', foreign_keys=[signup_referral_id], back_populates='signups')
def __init__(self, **kwargs):
self.own_referral_key = ReferralKey()
super().__init__(**kwargs)
class ReferralKey(Base):
__tablename__ = "referral_key"
id = Column(Integer, primary_key=True)
owner = relationship('User', foreign_keys=[User.own_referral_id], back_populates='own_referral_key', uselist=False)
signups = relationship('User', foreign_keys=[User.signup_referral_id], back_populates='signup_referral_key', uselist=True)
e = create_engine("sqlite://")
Base.metadata.create_all(e)
s = Session(e)
u1 = User()
s.add(u1)
s.commit()
u2 = User(signup_referral_id = u1.own_referral_id)
u3 = User(signup_referral_id = u1.own_referral_id)
s.add(u2)
s.add(u3)
s.commit()
print(u1.own_referral_key.signups)
推荐阅读
- python - 从 ArcMap 10.8 的 Python 窗口中的不同文件夹调用脚本
- powerbi - 在power bi中如何使用自定义模板更改表格列标题(可视表格标题)我正在尝试这个但不工作
- ios - iOS 上的 Ionic App 构建失败。Firebase 使用未声明的标识符“FIRInstanceID”
- image - 我可以将 smallbasic 图形窗口的背景更改为图像吗?
- android - 如何在android的日期选择器editTextView中启用键盘中的下一个选项?
- react-native - React Native 如何将多个图像上传到服务器(后端)
- python - Tensorflow ValueError:尺寸必须相等:LSTM + MDN
- javascript - 导航栏未在移动视图中显示
- java - 按哈希映射的值(按映射的值比较)对哈希映射的数组列表进行排序
- python - request.POST 有数据,但保存方法不会更新 django 中的数据库