database - Flask sqlalchemy,在这种情况下如何避免循环依赖?
问题描述
我已经连续两天在这个问题上头疼了,我仍然可以理解/找到一种方法来做到这一点,它看起来超级简单,但我显然忽略了一些东西(我对 DB 来说也是相当新的 :))。
我想要拥有所有者和宠物模型。宠物将“所有者 ID”作为外键,而所有者将“宠物”作为关系,到目前为止一切都很好。但现在我也希望所有者拥有一个写为“最喜欢的宠物”的“宠物 ID”。在两个模型中都有外键(彼此键)开始产生一堆不同的问题(根据我尝试解决它的方式而有所不同,但要么是循环依赖,要么是一些多路径错误)
我还注意到,如果我避免在 Owner 模型中使用“favourite_pet_id”-外键,只保留 favourite_pet-relationship,那么我不会在 DB 中的任何地方写这个(至少不可见),它只作为“relationship”存在?
这样做的正确方法是什么?提前致谢 !
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class Owner(db.Model):
id = db.Column(db.Integer, primary_key=True)
pets = db.relationship('Pet', foreign_keys='Pet.owner_id')
favourite_id = db.Column(db.Integer, db.ForeignKey('pet.id'))
favourite = db.relationship('Pet', uselist=False, foreign_keys='Owner.favourite_id')
class Pet(db.Model):
id =db.Column(db.Integer, primary_key=True)
owner_id = db.Column(db.Integer, db.ForeignKey('owner.id'))
owner = db.relationship('Owner', uselist=False, back_populates='pets', foreign_keys='Pet.owner_id')
o = Owner() # one owner
p1 = Pet() # pet 1
p2 = Pet() # pet 2
p1.owner=o # setting owner for pet1
p2.owner=o # setting owner for pet2
o.favourite=p2 # setting pet2 to be favourite
#db.session.add(o)
#db.session.add(p1)
#db.session.add(p2)
#db.session.commit()
print (p1.owner) # owner
print (p2.owner) # owner
print (p1) # pet 1
print (p2) # pet 2
print (o.pets) # owners pets
print (o.favourite) # favourite pet
解决方案
下面是您的代码的工作版本。关键是对关系(例如连接条件)更加明确,因为模型/表之间存在多种关系。
注意:虽然不是您的问题/请求的一部分,但我还重新格式化了一些 PEP8 一致性和可读性。后者是早期采用的好习惯,因为模型文件通常会快速增长,并且可能变得非常难以阅读、消化和调试。
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class Owner(db.Model):
id = db.Column(
db.Integer,
primary_key=True,
)
favourite_pet_id = db.Column(
db.Integer,
db.ForeignKey('pet.id'),
nullable=True,
)
favourite_pet = db.relationship(
'Pet',
uselist=False,
foreign_keys=[favourite_pet_id],
primaryjoin='Pet.owner_id == Owner.favourite_pet_id',
)
class Pet(db.Model):
id = db.Column(
db.Integer,
primary_key=True,
)
owner_id = db.Column(
db.Integer,
db.ForeignKey('owner.id'),
)
owner = db.relationship(
'Owner',
uselist=False,
foreign_keys=[owner_id],
primaryjoin='Pet.owner_id == Owner.id',
backref=db.backref(
'pets',
uselist=True,
),
)
db.create_all()
o = Owner() # one owner
p1 = Pet() # pet 1
p2 = Pet() # pet 2
p1.owner = o # setting owner for pet1
p2.owner = o # setting owner for pet2
o.favourite_pet = p2 # setting pet2 to be favourite
print(p1.owner) # owner
print(p2.owner) # owner
print(p1) # pet 1
print(p2) # pet 2
print(o.pets) # owners pets
print(o.favourite) # favourite pet
推荐阅读
- mysql - MySQL - 按月的最大汇总
- php - 单独获取ajax json数据
- python - 如果表存在,“如果不存在则创建表”查询仍然给出警告
- javascript - 节点js函数
- python - 如何在气流中设置两个工人
- angular - 如何用 Angular 6 做 RoleGuard?
- c# - c# 如何撤消 Encoding.UTF8.GetBytes 或转换为 File.ReadAllBytes
- webpack - 使用 html-webpack-plugin 创建 HTML 部分
- angular - Angular-Gridster2 - 网格项目在拖动时重叠
- r - 以 CSV 格式下载数据表