实际上,如果您想使用dumpdata
和之类的命令loaddata
来备份和恢复数据库中的选定对象,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()
. 不过,这将使代码与模型更加相关,因为您可能必须定义要在现有对象上更新哪些字段。上面显示的解决方案对模型的内容没有任何假设。