Python 使用自然键排除Django dumpdata中的主键
当启用自然键时,如何从Django的dumpdata生成的JSON中排除主键 我构建了一个我想“导出”的记录,以便其他人可以将其用作模板,方法是将其加载到具有相同模式的单独数据库中,而不会与同一模型中的其他记录发生冲突 据我所知,Django支持自然键,这似乎是NKs的设计初衷。我的记录有一个唯一的Python 使用自然键排除Django dumpdata中的主键,python,django,django-models,Python,Django,Django Models,当启用自然键时,如何从Django的dumpdata生成的JSON中排除主键 我构建了一个我想“导出”的记录,以便其他人可以将其用作模板,方法是将其加载到具有相同模式的单独数据库中,而不会与同一模型中的其他记录发生冲突 据我所知,Django支持自然键,这似乎是NKs的设计初衷。我的记录有一个唯一的名称字段,该字段也用作自然键 所以当我跑步时: from django.core import serializers from myapp.models import MyModel obj = M
名称
字段,该字段也用作自然键
所以当我跑步时:
from django.core import serializers
from myapp.models import MyModel
obj = MyModel.objects.get(id=123)
serializers.serialize('json', [obj], indent=4, use_natural_keys=True)
我希望输出类似于:
[
{
"model": "myapp.mymodel",
"fields": {
"name": "foo",
"create_date": "2011-09-22 12:00:00",
"create_user": [
"someusername"
]
}
}
]
然后,我可以使用loaddata将其加载到另一个数据库中,希望动态地为其分配一个新的主键。请注意,我的“create_user”字段是Django的auth.user模型的FK,它支持自然键,并作为其自然键而不是整数主键输出
然而,实际生成的是:
[
{
"pk": 123,
"model": "myapp.mymodel",
"fields": {
"name": "foo",
"create_date": "2011-09-22 12:00:00",
"create_user": [
"someusername"
]
}
}
]
这将明显与主键123冲突并覆盖任何现有记录
解决这个问题的最好方法是什么?我不想追溯性地将所有自动生成的主键整型字段更改为任何等效的自然键,因为这会导致性能下降,而且会耗费大量人力
编辑:这似乎是…2年前的事了…并且在很大程度上被忽略了…在单独的模块中重写
序列化程序
类:
from django.core.serializers.json import Serializer as JsonSerializer
class Serializer(JsonSerializer):
def end_object(self, obj):
self.objects.append({
"model" : smart_unicode(obj._meta),
"fields" : self._current,
# Original method adds the pk here
})
self._current = None
在Django中注册:
serializers.register_serializer("json_no_pk", "path.to.module.with.custom.serializer")
添加并使用它:
serializers.serialize('json_no_pk', [obj], indent=4, use_natural_keys=True)
json
的问题在于不能忽略pk
字段,因为在再次加载夹具数据时需要它。如果不存在,json将失败
$ python manage.py loaddata some_data.json
[...]
File ".../django/core/serializers/python.py", line 85, in Deserializer
data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])}
KeyError: 'pk'
正如在对的回答中所指出的,如果确实要省略pk
属性或仅用null
替换主键值,则可以使用yaml
或xml
import re
from django.core import serializers
some_objects = MyClass.objects.all()
s = serializers.serialize('json', some_objects, use_natural_keys=True)
# Replace id values with null - adjust the regex to your needs
s = re.sub('"pk": [0-9]{1,5}', '"pk": null', s)
为2018年及以后遇到此问题的任何人更新答案 有一种方法可以通过使用自然键和unique_-together方法省略主键。摘自: 您可以使用此命令测试:
python manage.py dumpdata app.model--pks 1,2,3--indent 4--natural primary--natural foreign>dumpdata.json;
自然键的序列化
那么,在序列化对象时,如何让Django发出一个自然键呢?首先,您需要添加另一种方法–这次是添加到模型本身:
班级人员(models.Model):
objects=PersonManager()
first_name=models.CharField(最大长度=100)
last_name=models.CharField(最大长度=100)
birthdate=models.DateField()
def自然_键(自):
返回(self.first\u name、self.last\u name)
类元:
共同唯一=(‘姓’、‘名’),)
该方法应始终返回一个自然键元组–在本例中为(名字、姓氏)。然后,当您调用serializers.serialize()
时,您将提供use\u natural\u foreign\u keys=True
或use\u natural\u primary\u keys=True
参数:
serializers.serialize('json',[book1,book2],缩进=2,使用\u natural\u foreign\u keys=True,使用\u natural\u primary\u keys=True)
当指定了use\u natural\u foreign\u keys=True
时,Django将使用natural\u key()
方法对定义该方法的类型的对象的任何外键引用进行序列化
如果指定了use\u natural\u primary\u keys=True
,Django将不会在该对象的序列化数据中提供主键,因为它可以在反序列化过程中计算:
{
"model": "store.person",
"fields": {
"first_name": "Douglas",
"last_name": "Adams",
"birth_date": "1952-03-11",
}
}
这正是我自己发现的解决方案。即使现在在json中,您似乎也可以省略
pk
字段。我更喜欢这种解决方案,但是如果没有pk值,反序列化会失败。您应该设置“pk”:无,
,而不是删除整个字段