Django灯具和OneToOneField

时间:2013-08-29 22:11:59

标签: python django

如上所述here对象是为与其他模型具有OneToOne关系的模型自动创建的。因此,如果我将Model1与O2O连接到Model2,并且将创建具有pk = 1的Model2的对象,则将自动创建Model2与model2_id = 1的对象。然后,如果我将数据从DB转储到json,我将有两个这些对象的记录。如果我将尝试使用loaddata将此数据加载到数据库 - 它将失败,因为Model2的对象将被创建两次,这将导致唯一的索引违例和IntegrityError。 有人找到了理智的解决方案吗?

P.S。
我使用Django 1.3.7

4 个答案:

答案 0 :(得分:4)

我做了类似的事情,不是用JSON而是用xml,而我的django是1.7,所以它可能不适合你。

  1. 在引用序列化对象时,可以使用natural keys。如果索引已被其他对象使用,这将防止混淆项目。
  2. 您可以使用dependencies来定义序列化的顺序(因此也就是反序列化)。
  3. 也许像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)

实际上,如果您想使用dumpdataloaddata之类的命令来备份和恢复数据库中的选择对象,O2O关系会变得棘手。

我们的软件遇到了类似的问题,我发现一个可能的工作解决方案是覆盖save()上的django.core.serializers.base.DeserializedObject方法,以实际处理“双倍”之前的时刻对象已保存。此时,您可能决定抛弃Django创建的默认O2O关系,让框架保存新的关系,或者使用XML或JSON文件中存储的值更新它。

在执行loaddata命令之前,你必须将覆盖的方法放在Django选择的地方。一种可能性是创建自己的命令,然后调用loaddata。在命令模块中,安装覆盖。以下有关此解决方案的详细信息:

  • 使用Django 1.8.x进行测试
  • 我们的O2O字段附加到Django User模型
  • 为了简化本例,我将调用附加的O2O字段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()的电话。它会使代码更加依赖于模型,因为您可能必须定义要在现有对象上更新的字段。上面显示的解决方案没有假设模型的内容。