2015-06-14 60 views
3

我的问题是储蓄需要互相引用,而不是仅仅使用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() 

这是做正确的方式,或者是有围绕节能两次另一种方式?

+0

什么是用例? – sobolevn

+0

@sobolevn这篇文章有很多但只有一个当前的版本,或许多可能的slu but,但只有一个主要的版本。 – jozxyqk

回答

3

没有办法绕过它,无论如何你都需要保存两个对象中的一个。

这是因为,在数据库级别,您需要保存一个对象以获取其ID。没有办法告诉sql数据库“保存这两个对象并将id分配给另一个对象上的这些字段”。因此,如果要手动执行此操作,则会为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你不能,因为不幸的是,立即检查。 [编辑:看来甲骨文可能支持推迟NOT NULL检查,因此,如果您正在使用Oracle,你可以尝试丢弃null=True,它应该工作。]

你可能要检查你的代码,如果反应如何在稍后的时候,当阅读数据库,如果由于某种原因(手动编辑,插入某处,...)one.current.owner != one

+0

非常丰富,特别是关于原子,谢谢! – jozxyqk

相关问题