有没有办法保存相互引用两次的模型?
Is there any way around saving models that reference each other twice?
我的问题是在保存需要相互引用的新模型时,而不仅仅是使用 related_name
查找,例如:
class Many:
owner = models.ForeignKey('One')
class One:
current = models.OneToOneField('Many')
默认情况下,它们有 null=False
,如果我错了,请纠正我,除非我改变其中一个关系,否则无法使用它们:
current = models.OneToOneField('Many', null=True)
原因是您无法将模型分配给关系,除非它已经保存。否则导致 ValueError: 'Cannot assign "<...>": "..." instance isn't saved in the database.'
.
但现在当我创建一对这样的对象时,我需要保存两次:
many = Many()
one = One()
one.save()
many.owner = one
many.save()
one.current = many
one.save()
这是正确的方法吗,还是有另一种方法可以节省两次?
没有办法,无论如何你都需要将其中一个对象保存两次。
这是因为,在数据库级别,您需要保存对象以获取其 ID。无法告诉 sql 数据库 "save those 2 objects and assign the ids to those fields on the other object"。因此,如果您要手动执行此操作,您将使用 FK 的 NULL 插入第一个对象,取回其 ID,使用第一个对象的 ID 插入第二个对象,取回其 ID,然后更新要设置的第一个对象FK。
您可以将整个事情封装在一个事务中。
所以你用 ORM 做的是你能得到的最接近的。您可能希望在此基础上添加以下内容:
1) 使用事务进行更改,如下所示:
from django.db import transaction
with transaction.atomic():
many, one = Many(), One()
one.save()
many.owner = one
many.save()
one.current = many
one.save(update_fields=['current']) # slight optimization here
2) 现在这被封装在一个事务中,您可能想要删除 null=True
。 但是你不能,不幸的是,这些会被立即检查。
[编辑:看来 Oracle 可能支持推迟 NOT NULL 检查,所以如果您使用的是 Oracle,您可以尝试删除 null=True
,它应该可以工作。]
你可能想检查你的代码如何反应,如果在稍后读取数据库时,如果出于某种原因(手动编辑,某处插入错误,...)one.current.owner != one
.
我的问题是在保存需要相互引用的新模型时,而不仅仅是使用 related_name
查找,例如:
class Many:
owner = models.ForeignKey('One')
class One:
current = models.OneToOneField('Many')
默认情况下,它们有 null=False
,如果我错了,请纠正我,除非我改变其中一个关系,否则无法使用它们:
current = models.OneToOneField('Many', null=True)
原因是您无法将模型分配给关系,除非它已经保存。否则导致 ValueError: 'Cannot assign "<...>": "..." instance isn't saved in the database.'
.
但现在当我创建一对这样的对象时,我需要保存两次:
many = Many()
one = One()
one.save()
many.owner = one
many.save()
one.current = many
one.save()
这是正确的方法吗,还是有另一种方法可以节省两次?
没有办法,无论如何你都需要将其中一个对象保存两次。
这是因为,在数据库级别,您需要保存对象以获取其 ID。无法告诉 sql 数据库 "save those 2 objects and assign the ids to those fields on the other object"。因此,如果您要手动执行此操作,您将使用 FK 的 NULL 插入第一个对象,取回其 ID,使用第一个对象的 ID 插入第二个对象,取回其 ID,然后更新要设置的第一个对象FK。 您可以将整个事情封装在一个事务中。
所以你用 ORM 做的是你能得到的最接近的。您可能希望在此基础上添加以下内容:
1) 使用事务进行更改,如下所示:
from django.db import transaction
with transaction.atomic():
many, one = Many(), One()
one.save()
many.owner = one
many.save()
one.current = many
one.save(update_fields=['current']) # slight optimization here
2) 现在这被封装在一个事务中,您可能想要删除 null=True
。 但是你不能,不幸的是,这些会被立即检查。
[编辑:看来 Oracle 可能支持推迟 NOT NULL 检查,所以如果您使用的是 Oracle,您可以尝试删除 null=True
,它应该可以工作。]
你可能想检查你的代码如何反应,如果在稍后读取数据库时,如果出于某种原因(手动编辑,某处插入错误,...)one.current.owner != one
.