私のすべての要件に適合する私のソリューションは次のとおりです。
- すべてのモデルに自然キーと一意の制約を
実装する
- 主キー ID を使用せずに各オブジェクトを一意に参照できるようにする
- django-extensions の
TimeStampedModelから各モデルをサブクラス化します
- 自動的に更新されるフィールドを追加
created
しmodified
ます
エクスポート用の 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
。