लघु संस्करण
आपको डेटा माइग्रेशन में सीधे प्रबंधन कमांड का उपयोग नहीं करना चाहिए 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),
]