前言
前言:许多时候实现目标功能都会遇到一张表里两个外键指向同一个表的主键,即为用一个表1关联另一个表2,表1里却使用了两个相同的外键去关联表2的主键,但是指向表2的事物是不同的,若不懂,直接看下列例子。
官方文档处理这类问题给的事例——文档链接。
一、事物例子
在Flask开发中,作者是在处理评论回复遇到的问题,回复评论表,需要被回复的用户id和用户的id,两个id都指向用户表,向用户表查询得到发出评论的用户和被回复的用户。
class Reply_comment(db.Model):
# 回复主评论表
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
r_comment = db.Column(db.BLOB, nullable=False)
r_comment_existence = db.Column(db.Integer, default=1)
r_comment_time = db.Column(db.DateTime, default=datetime.now)
comment_id = db.Column(db.Integer, db.ForeignKey('comment.id'))
#关联同一一个表————用户表,下两行是主要需要我们处理的
visitor_id = db.Column(db.Integer, db.ForeignKey('visitor.id'))
replied_visitor_id = db.Column(db.Integer, db.ForeignKey('visitor.id'))
class Visitor(db.Model):
# 用户表,不用太在意,只是被上表作为关联主键id作用
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(15), nullable=False)
email = db.Column(db.String(20), nullable=False)
rdategtime = db.Column(db.DateTime, default=datetime.now)
visitor_type = db.Column(db.Integer, default=3)
icon = db.Column(db.String(100))
面对两个外键 visitor_id 和 replied_visitor_id 指向同一表外键不做处理是不被允许的,强行运行就会报错,即使设置了普通的相关 relationship() 参照,报错会提示设置 foreign_keys 参数,只要根据报错提示处理即可。
二、处理方法
1.设置foreign_keys 参数
代码如下:
class Reply_comment(db.Model):
# 回复主评论表
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
r_comment = db.Column(db.BLOB, nullable=False)
r_comment_existence = db.Column(db.Integer, default=1)
r_comment_time = db.Column(db.DateTime, default=datetime.now)
comment_id = db.Column(db.Integer, db.ForeignKey('comment.id'))
visitor_id = db.Column(db.Integer, db.ForeignKey('visitor.id'))
replied_visitor_id = db.Column(db.Integer, db.ForeignKey('visitor.id'))
# 添加相关外键foreign_keys参数
visitor = db.relationship('Visitor', backref='reply_comment', foreign_keys=[visitor_id])
replied_visitor = db.relationship('Visitor', backref='replied_comment', foreign_keys=[replied_visitor_id])
在评论表里添加了 visitor 和 replied_visitor 关系参照,用户表不修改,一般建立 relationship() 参照关系是不需要迁移同步,但添加了 foreign_keys 参数是需要在数据库里面进行建立他们之间关系,所以注意:建立了 foreign_keys 参数必须把关系迁移同步到数据库。
2.注意!
注意:建立了 foreign_keys 参数,必须迁移同步到数据库。
foreign_keys=[visitor_id]
设置 foreign_keys 参数使用 [ ] 括号返回的值是一个对象,即使用 reply_comment.visitor 返回值是一个用户对象。
想获得其他类型,查看官方文档即可,给了相应的方法。
总结
总结:处理数据库还是令人恶心,人菜错误多,随便改一点错误又的喝一壶!
面对此类问题:一个表多个外键关联同一个表的主键时,需要添加foreign_keys 参数,并且需要迁移同步其关系。
追加总结:面对此处理表之间的关系时,一般是建立有名无实的外键关系,换言之就是:两个表之间是有关系,但是我们不在两表之间建立实质的外键关系,而是以我们自己懂的符号代表他们之间的关系。因为外键建立过多会影响数据库的查询速度,降低响应速度,有时还会带来一些其他的bug,因此在建立外键时,因谨慎考虑,尽量少建立或者不建立实质的外键关系。在使用时在后端自己查询再使用,比使用外键去查更快;比如本文的双外键也不应该建立实质的外键关系,而是建立他们之间的虚拟的外键关系,加快速度和避免互锁干死数据库。(21.10.4改)
参考文章:
Configuring how Relationship Joins — SQLAlchemy 1.4 Documentation