짧은 버전
당신은해야 하지 사용하는 loaddata
데이터 마이그레이션에서 직접 관리 명령을 사용합니다.
# Bad example for a data migration
from django.db import migrations
from django.core.management import call_command
def load_fixture(apps, schema_editor):
# No, it's wrong. DON'T DO THIS!
call_command('loaddata', 'your_data.json', app_label='yourapp')
class Migration(migrations.Migration):
dependencies = [
# Dependencies to other migrations
]
operations = [
migrations.RunPython(load_fixture),
]
긴 버전
loaddata
가 이용하는 django.core.serializers.python.Deserializer
마이그레이션에 기록 데이터를 역 직렬화하는 최신 모델을 사용합니다. 그것은 잘못된 행동입니다.
예를 들어 loaddata
관리 명령을 사용하여 고정 장치에서 데이터를로드 하는 데이터 마이그레이션이 있고 이미 개발 환경에 적용되어 있다고 가정합니다.
나중에 해당 모델에 새 필수 필드 를 추가하기로 결정하고 이를 수행하고 업데이트 된 모델에 대해 새 마이그레이션을 수행합니다 ( ./manage.py makemigrations
메시지가 표시 될 때 새 필드에 일회성 값을 제공 할 수 있음).
다음 마이그레이션을 실행하면 모든 것이 잘됩니다.
마지막으로 Django 애플리케이션 개발을 완료하고 프로덕션 서버에 배포합니다. 이제 프로덕션 환경에서 처음부터 전체 마이그레이션을 실행할 때입니다.
그러나 데이터 마이그레이션은 실패합니다 . loaddata
현재 코드를 나타내는 명령 의 역 직렬화 된 모델 을 추가 한 새 필수 필드에 대해 빈 데이터로 저장할 수 없기 때문 입니다. 원래 조명기에는 필요한 데이터가 없습니다!
그러나 새 필드에 필요한 데이터로 설비를 업데이트하더라도 데이터 마이그레이션은 여전히 실패합니다 . 데이터 마이그레이션이 실행 중일 때 해당 컬럼을 데이터베이스에 추가하는 다음 마이그레이션은 아직 적용되지 않습니다. 존재하지 않는 열에는 데이터를 저장할 수 없습니다!
결론 : 데이터 마이그레이션에서이loaddata
명령은 모델과 데이터베이스간에 잠재적 인 불일치를 유발합니다. 당신은 확실히해야 하지 데이터 마이그레이션에 직접 사용합니다.
해결책
loaddata
명령은 django.core.serializers.python._get_model
기능에 의존 하여 조명기에서 해당 모델을 가져 오며, 이는 모델의 최신 버전을 반환합니다. 역사적 모델을 얻기 위해 원숭이 패치를해야합니다.
(다음 코드는 Django 1.8.x에서 작동합니다)
# Good example for a data migration
from django.db import migrations
from django.core.serializers import base, python
from django.core.management import call_command
def load_fixture(apps, schema_editor):
# Save the old _get_model() function
old_get_model = python._get_model
# Define new _get_model() function here, which utilizes the apps argument to
# get the historical version of a model. This piece of code is directly stolen
# from django.core.serializers.python._get_model, unchanged. However, here it
# has a different context, specifically, the apps variable.
def _get_model(model_identifier):
try:
return apps.get_model(model_identifier)
except (LookupError, TypeError):
raise base.DeserializationError("Invalid model identifier: '%s'" % model_identifier)
# Replace the _get_model() function on the module, so loaddata can utilize it.
python._get_model = _get_model
try:
# Call loaddata command
call_command('loaddata', 'your_data.json', app_label='yourapp')
finally:
# Restore old _get_model() function
python._get_model = old_get_model
class Migration(migrations.Migration):
dependencies = [
# Dependencies to other migrations
]
operations = [
migrations.RunPython(load_fixture),
]