这是我的解决方案,它符合我的所有要求:
- 在所有模型上实现自然键和唯一约束
- 允许以独特的方式引用每个对象,而无需使用主键 ID
- 在 django-extensions 中
从TimeStampedModel子类化每个模型
创建用于导出的 Django 管理命令,该命令过滤数据子集并使用自然键对其进行序列化
baz = Baz.objects.filter(foo=bar)
yaz = Yaz.objects.filter(foo=bar)
objects = [baz, yaz]
flat_objects = list(itertools.chain.from_iterable(objects))
data = serializers.serialize("json", flat_objects, indent=3, use_natural_keys=True)
print(data)
创建用于导入的Django管理命令,读取序列化文件并遍历对象,如下所示:
- 如果数据库中不存在对象(通过自然键),则创建它
- 如果对象存在,请检查
modified
时间戳
- 如果导入的对象较新,请更新字段
- 如果导入的对象较旧,请不要更新(但打印警告)
代码示例:
# Open the file
with open(args[0]) as data_file:
json_str = data_file.read()
# Deserialize and iterate
for obj in serializers.deserialize("json", json_str, indent=3, use_natural_keys=True):
# Get model info
model_class = obj.object.__class__
natural_key = obj.object.natural_key()
manager = model_class._default_manager
# Delete PK value
obj.object.pk = None
try:
# Get the existing object
existing_obj = model_class.objects.get_by_natural_key(*natural_key)
# Check the timestamps
date_existing = existing_obj.modified
date_imported = obj.object.modified
if date_imported > date_existing:
# Update fields
for field in obj.object._meta.fields:
if field.editable and not field.primary_key:
imported_val = getattr(obj.object, field.name)
existing_val = getattr(existing_obj, field.name)
if existing_val != imported_val:
setattr(existing_obj, field.name, imported_val)
except ObjectDoesNotExist:
obj.save()
工作流程是首先调用python manage.py exportTool > data.json
,然后在另一个 django 实例(或相同)上调用python manage.py importTool data.json
。