如上所述here对象是为与其他模型具有OneToOne关系的模型自动创建的。因此,如果我将Model1与O2O连接到Model2,并且将创建具有pk = 1的Model2的对象,则将自动创建Model2与model2_id = 1的对象。然后,如果我将数据从DB转储到json,我将有两个这些对象的记录。如果我将尝试使用loaddata
将此数据加载到数据库 - 它将失败,因为Model2的对象将被创建两次,这将导致唯一的索引违例和IntegrityError
。
有人找到了理智的解决方案吗?
P.S。
我使用Django 1.3.7
答案 0 :(得分:4)
我做了类似的事情,不是用JSON而是用xml,而我的django是1.7,所以它可能不适合你。
也许像this one这样的类似帖子也很有用。
答案 1 :(得分:1)
转储数据夹具时,请确保使用--natural参数:
python manage.py dumpdata myapp --indent=4 --natural
https://docs.djangoproject.com/en/dev/ref/django-admin/#django-admin-option---natural
对于--natural-foreign
,它在1.7中被弃用了答案 2 :(得分:0)
您最终可能会使用South,这使数据迁移既简单又强大:
http://south.readthedocs.org/en/latest/about.html
使用Django 1.6,新的migrations module将替换旧的数据库命令并使南方过时。
答案 3 :(得分:0)
实际上,如果您想使用dumpdata
和loaddata
之类的命令来备份和恢复数据库中的选择对象,O2O关系会变得棘手。
我们的软件遇到了类似的问题,我发现一个可能的工作解决方案是覆盖save()
上的django.core.serializers.base.DeserializedObject
方法,以实际处理“双倍”之前的时刻对象已保存。此时,您可能决定抛弃Django创建的默认O2O关系,让框架保存新的关系,或者使用XML或JSON文件中存储的值更新它。
在执行loaddata
命令之前,你必须将覆盖的方法放在Django选择的地方。一种可能性是创建自己的命令,然后调用loaddata
。在命令模块中,安装覆盖。以下有关此解决方案的详细信息:
User
模型Attached
。# Overrides deserialization to affect OneToOneFields for Users correctly
import django.core.serializers.base
from django.contrib.auth.models import User
from your.attached.models import Attached #model with O2O field to User
_original_save = django.core.serializers.base.DeserializedObject.save
def save(self, *args, **kwargs):
if isinstance(self.object, Attached):
# if the user in question has an attached object, delete it
user = User.objects.get(pk=self.object.user_id)
if hasattr(user, 'attached'): user.attached.delete()
# use the built-in function for all other cases
_original_save(self, *args, **kwargs)
django.core.serializers.base.DeserializedObject.save = save
您可以修改上面的代码,而不是删除现有对象,如果您在if hasattr(...)
子句中避免删除,则更新它,使用来自序列化对象的值更新现有对象并跳过致_original_save()
的电话。它会使代码更加依赖于模型,因为您可能必须定义要在现有对象上更新的字段。上面显示的解决方案没有假设模型的内容。