Django 2.1

Migrations




django

Migrations

माइग्रेशन Django का तरीका है कि आप अपने डेटाबेस स्कीमा में अपने मॉडल (किसी क्षेत्र को जोड़ते हुए, किसी मॉडल को हटाकर, आदि) में परिवर्तन करने के तरीके हैं। वे ज्यादातर स्वचालित होने के लिए डिज़ाइन किए गए हैं, लेकिन आपको यह जानना होगा कि माइग्रेशन कब करना है, कब उन्हें चलाना है, और आम समस्याएं जिन्हें आप चला सकते हैं।

आज्ञा देता है

कई आदेश हैं जो आप माइग्रेशन और Django के डेटाबेस स्कीमा से निपटने के लिए उपयोग करने के लिए उपयोग करेंगे:

  • migrate , जो लागू करने और पलायन को रोकने के लिए जिम्मेदार है।
  • makemigrations , जो आपके मॉडल में किए गए परिवर्तनों के आधार पर नए माइग्रेशन बनाने के लिए ज़िम्मेदार है।
  • sqlmigrate , जो प्रवास के लिए SQL स्टेटमेंट प्रदर्शित करता है।
  • showmigrations , जो किसी प्रोजेक्ट के माइग्रेशन और उनकी स्थिति को सूचीबद्ध करता है।

आपको अपने डेटाबेस स्कीमा के लिए संस्करण नियंत्रण प्रणाली के रूप में माइग्रेशन के बारे में सोचना चाहिए। makemigrations आपके मॉडल को व्यक्तिगत माइग्रेशन फ़ाइलों में परिवर्तित करने के लिए उत्तरदायी है - जो आपके makemigrations अनुरूप है - और migrate उन लोगों को आपके डेटाबेस पर लागू करने के लिए ज़िम्मेदार है।

प्रत्येक एप्लिकेशन के लिए माइग्रेशन फ़ाइलें उस ऐप के अंदर "माइग्रेशन" निर्देशिका में रहती हैं, और इसके कोडबेस के भाग के रूप में, और इसके लिए प्रतिबद्ध होने के लिए डिज़ाइन की गई हैं। आपको उन्हें एक बार अपनी विकास मशीन पर बनाना चाहिए और उसके बाद अपने सहयोगियों की मशीनों, अपनी स्टेजिंग मशीनों और अंततः अपनी उत्पादन मशीनों पर समान माइग्रेशन चलाना चाहिए।

ध्यान दें

उस पैकेज के नाम को ओवरराइड करना संभव है जिसमें MIGRATION_MODULES सेटिंग को संशोधित करके प्रति-ऐप आधार पर माइग्रेशन शामिल हैं।

माइग्रेशन समान डेटासेट पर उसी तरह से चलेगा और लगातार परिणाम उत्पन्न करेगा, जिसका अर्थ है कि आप विकास और मंचन में जो देखते हैं, वही परिस्थितियों में, उत्पादन में वास्तव में क्या होगा।

Django आपके मॉडल या फ़ील्ड में किसी भी परिवर्तन के लिए माइग्रेशन बनाएगा - यहां तक ​​कि विकल्प जो डेटाबेस को प्रभावित नहीं करते हैं - जिस तरह से यह किसी फ़ील्ड को सही ढंग से फिर से संगठित कर सकता है, वह है इतिहास के सभी परिवर्तन, और आपको उन विकल्पों की आवश्यकता हो सकती है कुछ डेटा माइग्रेशन बाद में (उदाहरण के लिए, यदि आपने कस्टम वैधीकरण सेट किए हैं)।

बैकएंड सपोर्ट

माइग्रेशन का समर्थन सभी बैकएंड पर किया जाता है जो कि Django के जहाजों के साथ-साथ किसी भी तीसरे पक्ष के बैकेंड के साथ होता है, यदि उन्होंने स्कीमा परिवर्तन ( SchemaEditor वर्ग के माध्यम से किया गया) के समर्थन में प्रोग्राम किया है।

हालाँकि, कुछ डेटाबेस स्कीमा माइग्रेशन की तुलना में दूसरों की तुलना में अधिक सक्षम होते हैं; नीचे के कुछ कवर को कवर किया गया है।

PostgreSQL

स्कीमा समर्थन के संदर्भ में यहां पोस्टग्रेसीक्यूएल सभी डेटाबेसों में सबसे अधिक सक्षम है; एकमात्र चेतावनी यह है कि डिफ़ॉल्ट मानों के साथ कॉलम जोड़ने से तालिका का पूर्ण पुनर्लेखन होगा, समय के आकार के लिए आनुपातिक।

इस कारण से, यह अनुशंसा की जाती है कि आप हमेशा null=True साथ नए कॉलम बनाएं, क्योंकि इस तरह उन्हें तुरंत जोड़ा जाएगा।

माई एसक्यूएल

MySQL में स्कीमा परिवर्तन संचालन के आसपास लेनदेन के लिए समर्थन का अभाव है, जिसका अर्थ है कि यदि कोई माइग्रेशन लागू करने में विफल रहता है, तो आपको फिर से प्रयास करने के लिए परिवर्तनों को मैन्युअल रूप से अनपिक करना होगा (यह पहले के बिंदु पर वापस रोल करना असंभव है)।

इसके अलावा, MySQL लगभग हर स्कीमा ऑपरेशन के लिए तालिकाओं को पूरी तरह से फिर से लिखेगा और आम तौर पर कॉलम जोड़ने या हटाने के लिए तालिका में पंक्तियों की संख्या के लिए आनुपातिक समय लेता है। धीमी हार्डवेयर पर यह प्रति मिनट दस लाख पंक्तियों से भी बदतर हो सकता है - कुछ स्तंभों को केवल कुछ मिलियन पंक्तियों के साथ एक तालिका में जोड़ना आपकी साइट को दस मिनट के लिए लॉक कर सकता है।

अंत में, MySQL में कॉलम, टेबल और इंडेक्स के लिए नाम की लंबाई पर अपेक्षाकृत छोटी सीमाएं होती हैं, साथ ही सभी कॉलम के संयुक्त आकार पर एक सीमा होती है, जिसमें एक इंडेक्स कवर होता है। इसका मतलब है कि अन्य बैकएंड पर संभव होने वाले इंडेक्स MySQL के तहत बनाए जाने में विफल होंगे।

SQLite

SQLite में बहुत कम अंतर्निर्मित स्कीमा परिवर्तन समर्थन है, और इसलिए Django इसके द्वारा अनुकरण करने का प्रयास करता है:

  • नए स्कीमा के साथ एक नई तालिका बनाना
  • डेटा को कॉपी करना
  • पुरानी मेज को गिराना
  • मूल नाम से मिलान करने के लिए नई तालिका का नाम बदलना

यह प्रक्रिया आम तौर पर अच्छी तरह से काम करती है, लेकिन यह धीमी और कभी-कभी छोटी गाड़ी हो सकती है। यह अनुशंसा नहीं की जाती है कि आप उत्पादन वातावरण में SQLite चलाएं और माइग्रेट करें जब तक कि आप जोखिमों और उसकी सीमाओं के बारे में बहुत जागरूक नहीं हैं; साथ Django जहाजों का समर्थन डेवलपर्स को एक पूर्ण डेटाबेस की आवश्यकता के बिना कम जटिल Django परियोजनाओं को विकसित करने के लिए अपने स्थानीय मशीनों पर SQLite का उपयोग करने की अनुमति देने के लिए डिज़ाइन किया गया है।

कार्यप्रवाह

पलायन के साथ काम करना सरल है। अपने मॉडल में बदलाव करें - कहते हैं, एक फ़ील्ड जोड़ें और एक मॉडल निकालें - और उसके बाद makemigrations :

$ python manage.py makemigrations
Migrations for 'books':
  books/migrations/0003_auto.py:
    - Alter field author on book

आपके मॉडल स्कैन किए जाएंगे और वर्तमान में आपके माइग्रेशन फ़ाइलों में निहित संस्करणों की तुलना में, और फिर माइग्रेशन का एक नया सेट लिखा जाएगा। यह सुनिश्चित करने के लिए आउटपुट पढ़ना सुनिश्चित करें कि क्या makemigrations आपको लगता है कि आप बदल गए हैं - यह बिल्कुल सही नहीं है, और जटिल परिवर्तनों के लिए यह पता लगाना संभव नहीं है कि आप क्या उम्मीद करते हैं।

एक बार आपके पास अपनी नई माइग्रेशन फ़ाइलें आने के बाद, आपको यह सुनिश्चित करने के लिए अपने डेटाबेस पर लागू करना चाहिए कि वे अपेक्षित रूप से काम करते हैं:

$ python manage.py migrate
Operations to perform:
  Apply all migrations: books
Running migrations:
  Rendering model states... DONE
  Applying books.0003_auto... OK

माइग्रेशन लागू होने के बाद, माइग्रेशन करें और मॉडल एक ही कमिट के रूप में आपके वर्जन कंट्रोल सिस्टम में बदल जाते हैं - इस तरह, जब अन्य डेवलपर्स (या आपका प्रोडक्शन सर्वर) कोड की जांच करते हैं, तो वे दोनों ही आपके मॉडल में बदलाव कर देंगे। और साथ ही साथ प्रवास।

यदि आप माइग्रेशन को एक उत्पन्न नाम के बजाय एक सार्थक नाम देना चाहते हैं, तो आप makemigrations --name उपयोग कर सकते हैं: -

$ python manage.py makemigrations --name changed_my_model your_app_label

संस्करण नियंत्रण

क्योंकि माइग्रेशन संस्करण नियंत्रण में संग्रहीत किए जाते हैं, आप कभी-कभी ऐसी स्थितियों में आएंगे, जहां आप और एक अन्य डेवलपर दोनों ने एक ही समय में एक ही ऐप में माइग्रेशन किया है, जिसके परिणामस्वरूप एक ही नंबर के साथ दो माइग्रेशन होते हैं।

चिंता न करें - नंबर सिर्फ डेवलपर्स के संदर्भ के लिए हैं, Django बस परवाह करता है कि प्रत्येक प्रवास का एक अलग नाम है। माइग्रेशन निर्दिष्ट करते हैं कि वे कौन से अन्य माइग्रेशन पर निर्भर करते हैं - एक ही ऐप में पहले के माइग्रेशन सहित - फ़ाइल में, इसलिए यह पता लगाना संभव है कि एक ही ऐप के लिए दो नए माइग्रेशन हैं जो ऑर्डर नहीं किए गए हैं।

जब ऐसा होता है, तो Django आपको संकेत देगा और आपको कुछ विकल्प देगा। यदि यह सोचता है कि यह पर्याप्त सुरक्षित है, तो यह आपके लिए दो माइग्रेशनों को स्वचालित रूप से रैखिक बनाने की पेशकश करेगा। यदि नहीं, तो आपको स्वयं ही माइग्रेशन में जाना और संशोधित करना होगा - चिंता न करें, यह मुश्किल नहीं है, और नीचे माइग्रेशन फ़ाइलों में अधिक समझाया गया है।

निर्भरता

जबकि माइग्रेशन प्रति-ऐप हैं, आपके मॉडल द्वारा निहित टेबल और संबंध एक समय में केवल एक ऐप के लिए बनाए जाने के लिए बहुत जटिल हैं। जब आप एक माइग्रेशन बनाते हैं, जिसे चलाने के लिए कुछ और की आवश्यकता होती है - उदाहरण के लिए, आप अपनी books में एक ForeignKey को अपने authors ऐप में जोड़ते हैं - परिणामस्वरूप प्रवासन में authors प्रवास पर निर्भरता होगी।

इसका मतलब यह है कि जब आप माइग्रेशन चलाते हैं, तो authors माइग्रेशन पहले चलाता है और तालिका को ForeignKey सन्दर्भ बनाता है, और फिर ForeignKey कॉलम बनाने वाला माइग्रेशन बाद में चलता है और बाधा बनाता है। यदि ऐसा नहीं होता है, तो माइग्रेशन ForeignKey कॉलम को टेबल के बिना बनाने की कोशिश करेगा, जो मौजूदा है और आपके डेटाबेस में कोई त्रुटि है।

यह निर्भरता व्यवहार सबसे अधिक माइग्रेशन परिचालनों को प्रभावित करता है जहां आप किसी एक ऐप तक सीमित रहते हैं। एक ही ऐप पर प्रतिबंध (या तो makemigrations या migrate ) एक सबसे अच्छा प्रयास वादा है, और गारंटी नहीं है; निर्भरता को सही करने के लिए जिन अन्य ऐप्स का उपयोग करना आवश्यक है, वे होंगे।

माइग्रेशन फ़ाइलें

माइग्रेशन को एक ऑन-डिस्क प्रारूप के रूप में संग्रहीत किया जाता है, जिसे "माइग्रेशन फ़ाइलों" के रूप में संदर्भित किया जाता है। ये फाइलें वास्तव में सामान्य पायथन फाइलें हैं, जो कि एक घोषित शैली में लिखी गई एक सहमति-युक्त वस्तु लेआउट के साथ हैं।

एक मूल माइग्रेशन फ़ाइल इस तरह दिखाई देती है:

from django.db import migrations, models

class Migration(migrations.Migration):

    dependencies = [('migrations', '0001_initial')]

    operations = [
        migrations.DeleteModel('Tribble'),
        migrations.AddField('Author', 'rating', models.IntegerField(default=0)),
    ]

जब यह माइग्रेशन फ़ाइल (एक पायथन मॉड्यूल के रूप में) लोड करता है, तो Django क्या देखता है, django.db.migrations.Migration की एक उपवर्ग है। Migration नामक Migration । यह तब चार विशेषताओं के लिए इस वस्तु का निरीक्षण करता है, जिनमें से केवल दो का उपयोग अधिकांश समय किया जाता है:

  • dependencies , यह एक पलायन की एक सूची पर निर्भर करता है।
  • operations , Operation वर्गों की एक सूची जो परिभाषित करती है कि यह प्रवास क्या करता है।

संचालन कुंजी हैं; वे घोषणात्मक निर्देशों का एक समूह हैं जो Django को बताते हैं कि स्कीमा में क्या बदलाव किए जाने की आवश्यकता है। Django उन्हें स्कैन करता है और सभी एप्लिकेशन में सभी स्कीमा परिवर्तनों का इन-मेमोरी प्रतिनिधित्व बनाता है, और इसका उपयोग SQL को उत्पन्न करने के लिए करता है जो स्कीमा परिवर्तन करता है।

उस इन-मेमोरी संरचना का उपयोग यह जानने के लिए भी किया जाता है कि आपके मॉडल और आपके माइग्रेशन की वर्तमान स्थिति में क्या अंतर हैं; Django सभी परिवर्तनों के माध्यम से चलता है, आदेश में, अपने मॉडलों की स्थिति के साथ आने के लिए मॉडल के एक इन-मेमोरी सेट पर पिछली बार जब आप makemigrations भागते makemigrations । इसके बाद इन मॉडल्स का उपयोग आपकी मॉडेल की फाइलों की तुलना करने के लिए किया जाता है।

आपको शायद ही कभी, अगर हाथ से माइग्रेशन फ़ाइलों को संपादित करने की आवश्यकता है, लेकिन यदि आप की आवश्यकता है तो उन्हें मैन्युअल रूप से लिखना संभव है। अधिक जटिल कार्यों में से कुछ ऑटोडेटेक्टेबल नहीं हैं और केवल हाथ से लिखे गए माइग्रेशन के माध्यम से उपलब्ध हैं, इसलिए यदि आपके पास है तो उन्हें संपादित करने के बारे में डरें नहीं।

कस्टम फील्ड्स

आप पहले से ही माइग्रेट किए गए कस्टम फ़ील्ड में बिना TypeError बढ़ाए स्थिति संबंधी तर्कों की संख्या को संशोधित नहीं कर सकते। पुराना माइग्रेशन पुराने हस्ताक्षर के साथ संशोधित __init__ विधि को कॉल करेगा। इसलिए यदि आपको एक नए तर्क की आवश्यकता है, तो कृपया एक कीवर्ड तर्क बनाएं और कंस्ट्रक्टर assert 'argument_name' in kwargs में assert 'argument_name' in kwargs जैसा कुछ जोड़ें।

मॉडल प्रबंधक

आप वैकल्पिक रूप से प्रबंधकों को माइग्रेशन में RunPython कर सकते हैं और उन्हें RunPython ऑपरेशन में उपलब्ध RunPython । यह प्रबंधक वर्ग पर एक use_in_migrations विशेषता को परिभाषित करके किया जाता है:

class MyManager(models.Manager):
    use_in_migrations = True

class MyModel(models.Model):
    objects = MyManager()

यदि आप गतिशील रूप से प्रबंधक वर्ग उत्पन्न करने के लिए from_queryset() फ़ंक्शन का उपयोग कर रहे हैं, तो आपको इसे आयात करने योग्य बनाने के लिए उत्पन्न वर्ग से इनहेरिट करने की आवश्यकता है:

class MyManager(MyBaseManager.from_queryset(CustomQuerySet)):
    use_in_migrations = True

class MyModel(models.Model):
    objects = MyManager()

कृपया साथ आने वाले निहितार्थों को देखने के लिए प्रवासन में ऐतिहासिक मॉडल के बारे में नोट देखें।

प्रारंभिक माइग्रेशन

Migration.initial

किसी एप्लिकेशन के लिए "प्रारंभिक माइग्रेशन" वे माइग्रेशन हैं जो उस ऐप की तालिकाओं का पहला संस्करण बनाते हैं। आमतौर पर एक ऐप में सिर्फ एक प्रारंभिक माइग्रेशन होगा, लेकिन कुछ जटिल मॉडल अन्योन्याश्रितियों के कुछ मामलों में इसके दो या अधिक हो सकते हैं।

प्रारंभिक माइग्रेशन को माइग्रेशन क्लास पर एक initial = True क्लास विशेषता के साथ चिह्नित किया जाता है। यदि initial वर्ग विशेषता नहीं मिली है, तो एक माइग्रेशन को "प्रारंभिक" माना जाएगा यदि यह ऐप में पहला माइग्रेशन है (यानी यदि एक ही ऐप में किसी अन्य माइग्रेशन पर इसकी कोई निर्भरता नहीं है)।

जब migrate --fake-initial विकल्प का उपयोग किया जाता है, तो इन प्रारंभिक माइग्रेशनों का विशेष रूप से इलाज किया जाता है। एक या अधिक टेबल ( CreateModel ऑपरेशन) बनाने वाले प्रारंभिक माइग्रेशन के लिए, Django चेक करता है कि डेटाबेस में पहले से मौजूद सभी टेबल मौजूद हैं और यदि ऐसा है तो माइग्रेशन फर्जी है। इसी तरह, एक प्रारंभिक माइग्रेशन जो एक या अधिक फ़ील्ड ( AddField ऑपरेशन) जोड़ता है, के लिए Django जाँच करता है कि संबंधित सभी कॉलम पहले से ही डेटाबेस में मौजूद हैं और यदि ऐसा है तो माइग्रेशन को नकली-लागू करता है। बिना --fake-initial , प्रारंभिक माइग्रेशन को किसी अन्य माइग्रेशन से अलग नहीं माना जाता है।

इतिहास की संगति

जैसा कि पहले चर्चा की गई है, दो विकास शाखाओं में शामिल होने पर आपको मैन्युअल रूप से माइग्रेशन को रैखिक बनाने की आवश्यकता हो सकती है। माइग्रेशन निर्भरताओं को संपादित करते समय, आप अनजाने में एक असंगत इतिहास स्थिति बना सकते हैं जहां एक माइग्रेशन लागू किया गया है, लेकिन इसकी कुछ निर्भरताएं नहीं हैं। यह एक मजबूत संकेत है कि निर्भरताएं गलत हैं, इसलिए Django माइग्रेशन चलाने से इनकार कर देगा या जब तक तय नहीं हो जाता है तब तक नए माइग्रेशन बना सकते हैं। कई डेटाबेस का उपयोग करते समय, आप डेटाबेस राउटर की allow_migrate() विधि का उपयोग कर सकते हैं ताकि यह नियंत्रित किया जा सके कि कौन सा डेटाबेस लगातार इतिहास की जांच करता है।

ऐप्स में माइग्रेशन जोड़ना

नए एप्लिकेशन में माइग्रेशन जोड़ना सीधा है - वे माइग्रेशन स्वीकार करने के लिए पूर्व- makemigrations आते हैं, और इसलिए कुछ परिवर्तन करने के बाद बस makemigrations चलाएं।

यदि आपके ऐप में पहले से ही मॉडल और डेटाबेस टेबल हैं, और अभी तक माइग्रेशन नहीं हैं (उदाहरण के लिए, आपने इसे पिछले Django संस्करण के विरुद्ध बनाया है), तो आपको माइग्रेशन का उपयोग करने के लिए इसे परिवर्तित करना होगा; यह एक सरल प्रक्रिया है:

$ python manage.py makemigrations your_app_label

यह आपके ऐप के लिए एक नया प्रारंभिक माइग्रेशन बना देगा। अब, python manage.py migrate --fake-initial , और Django यह पता लगाएगा कि आपके पास एक प्रारंभिक माइग्रेशन है और यह कि तालिकाएँ जो पहले से ही बनाना चाहते हैं, और पहले से ही लागू माइग्रेशन को चिह्नित करेगा। ( migrate --fake-initial ध्वज के बिना, कमांड में त्रुटि होगी क्योंकि यह जो टेबल बनाना चाहते हैं, वे पहले से मौजूद हैं।)

ध्यान दें कि यह केवल दो काम करता है:

  • आपने अपनी तालिकाएँ बनाने के बाद से अपने मॉडल नहीं बदले हैं। काम करने के लिए माइग्रेशन के लिए, आपको पहले प्रारंभिक माइग्रेशन करना होगा और फिर परिवर्तन करना होगा, क्योंकि Django माइग्रेशन फ़ाइलों के विरुद्ध परिवर्तनों की तुलना करता है, डेटाबेस की नहीं।
  • आपने अपने डेटाबेस को मैन्युअल रूप से संपादित नहीं किया है - Django यह पता लगाने में सक्षम नहीं होगा कि आपका डेटाबेस आपके मॉडल से मेल नहीं खाता है, आपको बस त्रुटियां मिलेंगी जब माइग्रेशन उन तालिकाओं को संशोधित करने का प्रयास करता है।

ऐतिहासिक मॉडल

जब आप माइग्रेशन चलाते हैं, तो Django माइग्रेशन फ़ाइलों में संग्रहीत आपके मॉडल के ऐतिहासिक संस्करणों से काम कर रहा है। यदि आप RunPython ऑपरेशन का उपयोग करके पायथन कोड लिखते हैं, या यदि आपके पास अपने डेटाबेस राउटर पर allow_migrate विधियाँ हैं, तो आपको सीधे आयात करने के बजाय इन ऐतिहासिक मॉडल संस्करणों का उपयोग करने की आवश्यकता है

चेतावनी

यदि आप ऐतिहासिक मॉडल का उपयोग करने के बजाय सीधे मॉडल आयात करते हैं, तो आपका माइग्रेशन प्रारंभ में काम कर सकता है , लेकिन भविष्य में विफल हो जाएगा जब आप पुराने माइग्रेशन को फिर से चलाने की कोशिश करते हैं (आमतौर पर, जब आप एक नया इंस्टॉलेशन सेट करते हैं और सेट करने के लिए सभी माइग्रेशन चलाते हैं डेटाबेस)।

इसका मतलब यह है कि ऐतिहासिक मॉडल समस्याएं तुरंत स्पष्ट नहीं हो सकती हैं। यदि आप इस तरह की विफलता में भाग लेते हैं, तो सीधे आयात के बजाय ऐतिहासिक मॉडल का उपयोग करने और उन परिवर्तनों को करने के लिए माइग्रेशन को संपादित करना ठीक है।

क्योंकि मनमाने पायथन कोड को अनुक्रमित करना असंभव है, इन ऐतिहासिक मॉडलों में कोई कस्टम तरीके नहीं होंगे जिन्हें आपने परिभाषित किया है। हालाँकि, उनके पास समान फ़ील्ड्स, रिलेशनशिप, मैनेजर होंगे (जो उन लोगों तक सीमित होंगे, use_in_migrations = True ) और Meta विकल्प (भी संस्करण किए गए हैं, इसलिए वे आपके वर्तमान से भिन्न हो सकते हैं)।

चेतावनी

इसका मतलब यह है कि आपके पास माइग्रेशन में एक्सेस करने पर ऑब्जेक्ट पर कस्टम save() तरीके नहीं होंगे, और आपके पास कोई कस्टम कंस्ट्रक्टर या इंस्टेंस मेथड नहीं होंगे। उचित योजना!

फ़ील्ड विकल्पों जैसे कि upload_to और limit_choices_to और मॉडल प्रबंधक घोषणाओं का उपयोग करने वाले प्रबंधकों के साथ use_in_migrations = True माइग्रेशन में क्रमबद्ध होते हैं, इसलिए फ़ंक्शंस और कक्षाओं को तब तक रखना होगा जब तक कि एक माइग्रेशन उन्हें संदर्भित नहीं करता है। किसी भी कस्टम मॉडल फ़ील्ड को रखने की आवश्यकता होगी, क्योंकि ये सीधे माइग्रेशन द्वारा आयात किए जाते हैं।

इसके अलावा, मॉडल के आधार वर्गों को केवल संकेत के रूप में संग्रहीत किया जाता है, इसलिए आपको हमेशा आधार कक्षाओं को तब तक के लिए रखना चाहिए जब तक कि एक प्रवास होता है जिसमें उनका संदर्भ होता है। प्लस साइड पर, इन बेस कक्षाओं से विधियां और प्रबंधक सामान्य रूप से विरासत में मिलते हैं, इसलिए यदि आपको इन तक पहुंच की आवश्यकता है, तो आप उन्हें सुपरक्लास में जाने का विकल्प चुन सकते हैं।

पुराने संदर्भों को हटाने के लिए, आप माइग्रेशन स्क्वैश कर सकते हैं या, यदि कई संदर्भ नहीं हैं, तो उन्हें माइग्रेशन फ़ाइलों में कॉपी करें।

मॉडल फ़ील्ड हटाते समय विचार

पिछले अनुभाग में वर्णित "ऐतिहासिक कार्यों के संदर्भ" विचार के समान, अपने प्रोजेक्ट या तीसरे पक्ष के ऐप से कस्टम मॉडल फ़ील्ड को हटाने से पुराने माइग्रेशन में संदर्भित होने पर समस्या उत्पन्न होगी।

इस स्थिति में मदद करने के लिए, Django सिस्टम चेक फ्रेमवर्क का उपयोग करके मॉडल क्षेत्र की वृद्धि के साथ सहायता करने के लिए कुछ मॉडल फ़ील्ड विशेषताएँ प्रदान करता है

निम्न के समान अपने मॉडल फ़ील्ड में system_check_deprecated_details विशेषता जोड़ें:

class IPAddressField(Field):
    system_check_deprecated_details = {
        'msg': (
            'IPAddressField has been deprecated. Support for it (except '
            'in historical migrations) will be removed in Django 1.9.'
        ),
        'hint': 'Use GenericIPAddressField instead.',  # optional
        'id': 'fields.W900',  # pick a unique ID for your field.
    }

आपके चयन की एक अवधी अवधि (Django में फ़ील्ड्स के लिए दो या तीन फ़ीचर रिलीज़) के बाद, system_check_deprecated_details विशेषता को system_check_removed_details और शब्दकोश को समान अपडेट करें:

class IPAddressField(Field):
    system_check_removed_details = {
        'msg': (
            'IPAddressField has been removed except for support in '
            'historical migrations.'
        ),
        'hint': 'Use GenericIPAddressField instead.',
        'id': 'fields.E900',  # pick a unique ID for your field.
    }

आपको उस क्षेत्र के तरीकों को रखना चाहिए जो डेटाबेस माइग्रेशन जैसे कि __init__() , get_internal_type() , और get_internal_type() में संचालित करने के लिए आवश्यक हैं। इस स्टब क्षेत्र को किसी भी माइग्रेशन के रूप में लंबे समय तक रखें, जो क्षेत्र को संदर्भित करता है। उदाहरण के लिए, पलायन को रोकने और पुराने को हटाने के बाद, आपको क्षेत्र को पूरी तरह से हटाने में सक्षम होना चाहिए।

डेटा माइग्रेशन

डेटाबेस स्कीमा को बदलने के साथ-साथ, आप चाहें तो स्कीमा के साथ मिलकर डेटाबेस में डेटा को बदलने के लिए माइग्रेशन का उपयोग भी कर सकते हैं।

डेटा को बदलने वाले माइग्रेशन को आमतौर पर "डेटा माइग्रेशन" कहा जाता है; वे अलग-अलग माइग्रेशन के रूप में लिखे गए हैं, जो आपके स्कीमा माइग्रेशन के साथ बैठे हैं।

Django स्वचालित रूप से आपके लिए डेटा माइग्रेशन उत्पन्न नहीं कर सकता, क्योंकि यह स्कीमा माइग्रेशन के साथ करता है, लेकिन उन्हें लिखना बहुत कठिन नहीं है। Django में माइग्रेशन फ़ाइलें Operations , और आपके द्वारा डेटा माइग्रेशन के लिए उपयोग किया जाने वाला मुख्य ऑपरेशन RunPython

शुरू करने के लिए, एक खाली माइग्रेशन फ़ाइल से आप काम कर सकते हैं (Django फ़ाइल को सही जगह पर रखेगा, एक नाम सुझाएगा, और आपके लिए निर्भरता जोड़ देगा):

python manage.py makemigrations --empty yourappname

फिर, फ़ाइल खोलें; यह कुछ इस तरह दिखना चाहिए:

# Generated by Django A.B on YYYY-MM-DD HH:MM
from django.db import migrations

class Migration(migrations.Migration):

    dependencies = [
        ('yourappname', '0001_initial'),
    ]

    operations = [
    ]

अब, आपको बस एक नया फ़ंक्शन बनाने की आवश्यकता है और RunPython उपयोग करें। RunPython अपने तर्क के रूप में एक RunPython उम्मीद करता है जो दो तर्क लेता है - पहला एक ऐप रजिस्ट्री है जिसमें आपके सभी मॉडलों के ऐतिहासिक संस्करण हैं जो इसे मैच करने के लिए लोड करते हैं जहां आपके इतिहास में माइग्रेशन बैठता है, और दूसरा एक SchemaEditor , जिसे आप कर सकते हैं डेटाबेस स्कीमा परिवर्तन को मैन्युअल रूप से प्रभावित करने के लिए उपयोग करें (लेकिन सावधान रहें, ऐसा करने से माइग्रेशन ऑटोडेक्टर को भ्रमित किया जा सकता है!)

आइए एक सरल माइग्रेशन लिखें जो हमारे नए name फ़ील्ड को first_name और last_name के संयुक्त मूल्यों के साथ पॉप्युलेट करता है (हम अपनी इंद्रियों पर आए हैं और महसूस किया है कि हर किसी के पास पहले और अंतिम नाम नहीं हैं)। हमें केवल ऐतिहासिक मॉडल का उपयोग करना है और पंक्तियों पर पुनरावृति करना है:

from django.db import migrations

def combine_names(apps, schema_editor):
    # We can't import the Person model directly as it may be a newer
    # version than this migration expects. We use the historical version.
    Person = apps.get_model('yourappname', 'Person')
    for person in Person.objects.all():
        person.name = '%s %s' % (person.first_name, person.last_name)
        person.save()

class Migration(migrations.Migration):

    dependencies = [
        ('yourappname', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(combine_names),
    ]

एक बार ऐसा हो जाने के बाद, हम बस python manage.py migrate को सामान्य रूप से चला सकते हैं और डेटा माइग्रेशन अन्य माइग्रेशन के साथ जगह में चलेगा।

जब आप पीछे की ओर पलायन करते हैं, तो आप जो भी तर्क निष्पादित करना चाहते हैं, उसे चलाने के लिए आप RunPython लिए दूसरा RunPython करने योग्य पास कर सकते हैं। यदि यह कॉल करने योग्य छोड़ा जाता है, तो पीछे की ओर पलायन एक अपवाद बढ़ाएगा।

अन्य ऐप से मॉडल एक्सेस करना

RunPython फ़ंक्शन लिखते समय, जिसमें माइग्रेशन स्थित है, के अलावा अन्य एप्लिकेशन के मॉडल का उपयोग करता है, माइग्रेशन की dependencies विशेषता में शामिल प्रत्येक ऐप का नवीनतम माइग्रेशन शामिल होना चाहिए, अन्यथा आपको इसके समान त्रुटि मिल सकती है: LookupError: No installed app with label 'myappname' जब आप apps.get_model() का उपयोग करके apps.get_model() फ़ंक्शन में मॉडल को पुनः प्राप्त करने का प्रयास करते हैं, तो LookupError: No installed app with label 'myappname'

निम्नलिखित उदाहरण में, हमारे पास app1 1 में एक माइग्रेशन है जिसे app1 में मॉडल का उपयोग करने की आवश्यकता है। हम move_m1 के ब्योरे से चिंतित नहीं हैं, इस तथ्य के अलावा कि इसे दोनों ऐप से मॉडल एक्सेस करने की आवश्यकता होगी। इसलिए हमने एक निर्भरता जोड़ी है जो app2 के अंतिम प्रवास को निर्दिष्ट करती है:

class Migration(migrations.Migration):

    dependencies = [
        ('app1', '0001_initial'),
        # added dependency to enable using models from app2 in move_m1
        ('app2', '0004_foobar'),
    ]

    operations = [
        migrations.RunPython(move_m1),
    ]

अधिक उन्नत पलायन

यदि आप अधिक उन्नत माइग्रेशन परिचालनों में रुचि रखते हैं, या अपना स्वयं का लेखन करने में सक्षम होना चाहते हैं, तो Operations देखें और Operations लिखने पर "कैसे-करें" देखें।

पलायन पर अंकुश

आपको स्वतंत्र रूप से माइग्रेशन बनाने के लिए प्रोत्साहित किया जाता है और इस बारे में चिंता न करें कि आपके पास कितने हैं; माइग्रेशन कोड बहुत मंदी के बिना एक समय में सैकड़ों से निपटने के लिए अनुकूलित है। हालाँकि, आखिरकार आप कई सौ माइग्रेशन से बस कुछ ही समय में वापस जाना चाहेंगे, और यहीं स्क्वैशिंग आती है।

स्क्वैशिंग एक से नीचे (या कभी-कभी कुछ) माइग्रेशन के लिए कई माइग्रेशन के मौजूदा सेट को कम करने का कार्य है जो अभी भी समान परिवर्तनों का प्रतिनिधित्व करते हैं।

Django आपके सभी मौजूदा माइग्रेशनों को ले कर, उनके Operation s को निकाल कर और उन सभी को अनुक्रम में रखता है, और फिर सूची की लंबाई को कम करने के लिए एक अनुकूलक चला रहा है - उदाहरण के लिए, यह जानता है कि CreateModel और DeleteModel प्रत्येक को रद्द करते हैं अन्य बाहर, और यह जानता है कि AddField CreateModel में लुढ़का जा सकता है।

एक बार ऑपरेशन अनुक्रम को जितना संभव हो उतना कम कर दिया गया है - संभव राशि इस बात पर निर्भर करती है कि आपके मॉडल कितने बारीकी से RunSQL हैं और यदि आपके पास कोई RunSQL या RunPython ऑपरेशंस हैं (जिन्हें तब तक ऑप्टिमाइज़ नहीं किया जा सकता है जब तक कि उन्हें elidable के रूप में चिह्नित नहीं किया elidable ) - Django फिर इसे वापस माइग्रेशन फ़ाइलों के एक नए सेट में लिखें।

इन फ़ाइलों को यह कहने के लिए चिह्नित किया जाता है कि वे पहले से स्क्वैस्ड माइग्रेशन को प्रतिस्थापित करते हैं, इसलिए वे पुरानी माइग्रेशन फ़ाइलों के साथ सह-अस्तित्व में आ सकते हैं, और Django समझदारी से उन दोनों के बीच स्विच करेगा जहां आप इतिहास में हैं। यदि आप अभी भी माइग्रेशन के सेट के माध्यम से भाग-भाग कर रहे हैं जिसे आपने स्खलित किया है, तो यह उनका उपयोग तब तक करता रहेगा जब तक कि यह अंत तक हिट न हो जाए और फिर स्क्वैश किए गए इतिहास पर स्विच हो जाए, जबकि नए इंस्टॉलेशन केवल नए स्क्वैश माइग्रेशन का उपयोग करेंगे और सभी पुराने को छोड़ देंगे लोगों को।

यह आपको स्क्वैश करने में सक्षम बनाता है और वर्तमान में उत्पादन में पूरी तरह से अप-टू-डेट नहीं है। सिफारिश की गई प्रक्रिया पुरानी फाइलों को रखने, स्क्वैश करने और जारी करने की है, तब तक प्रतीक्षा करें जब तक कि सभी सिस्टम नई रिलीज के साथ अपग्रेड न हो जाएं (या यदि आप एक तृतीय-पक्ष प्रोजेक्ट हैं, तो बस अपने उपयोगकर्ताओं को बिना किसी लंघन के क्रम में रिलीज को सुनिश्चित करें) , और फिर पुरानी फ़ाइलों को हटा दें, कमिट करें और दूसरी रिलीज़ करें।

कमांड जो यह सब वापस करता है वह squashmigrations - बस इसे ऐप लेबल और माइग्रेशन नाम पास करें जिसे आप स्क्वैश करना चाहते हैं, और यह काम करने के लिए मिलेगा:

$ ./manage.py squashmigrations myapp 0004
Will squash the following migrations:
 - 0001_initial
 - 0002_some_change
 - 0003_another_change
 - 0004_undo_something
Do you wish to proceed? [yN] y
Optimizing...
  Optimized from 12 operations to 7 operations.
Created new squashed migration /home/andrew/Programs/DjangoTest/test/migrations/0001_squashed_0004_undo_somthing.py
  You should commit this migration but leave the old ones in place;
  the new migration will be used for new installs. Once you are sure
  all instances of the codebase have applied the migrations you squashed,
  you can delete them.

यदि आप squashmigrations --squashed-name माइग्रेशन का नाम सेट करना चाहते हैं, तो squashmigrations --squashed-name ऑप्शन का उपयोग करें।

ध्यान दें कि Django में मॉडल निर्भरता बहुत जटिल हो सकती है, और स्क्वैशिंग के परिणामस्वरूप माइग्रेशन हो सकते हैं जो नहीं चलते हैं; या तो गलत-अनुकूलित (जिस मामले में आप फिर से कोशिश कर सकते हैं --no-optimize , हालांकि आपको एक समस्या की रिपोर्ट भी करनी चाहिए), या एक CircularDependencyError साथ, जिस स्थिति में आप इसे मैन्युअल रूप से हल कर सकते हैं।

मैन्युअल रूप से एक CircularDependencyError हल करने के लिए, एक विदेशी माइग्रेशन को एक अलग माइग्रेशन में परिपत्रकी निर्भरता लूप से अलग करें, और इसके साथ अन्य ऐप पर निर्भरता को स्थानांतरित करें। यदि आप अनिश्चित हैं, तो देखें कि आपके मॉडल से ब्रांड के नए माइग्रेशन बनाने के लिए पूछे जाने पर makemigrations समस्या से कैसे makemigrations हैं। Django के भविष्य के रिलीज में, squashmigrations को स्वयं इन त्रुटियों को हल करने के प्रयास के लिए अद्यतन किया जाएगा।

एक बार जब आप अपना माइग्रेशन स्क्वैश कर लेते हैं, तो आपको इसे उन माइग्रेशनों के साथ भेजना चाहिए जो इसे बदलता है और इस परिवर्तन को आपके एप्लिकेशन के सभी चल रहे इंस्टेंस में वितरित करता है, जिससे यह सुनिश्चित होता है कि वे अपने डेटाबेस में बदलाव को स्टोर migrate लिए migrate चलाते migrate

फिर आपको स्क्वॉस्ड माइग्रेशन को सामान्य माइग्रेशन में परिवर्तित करना होगा:

  • सभी माइग्रेशन फ़ाइलों को हटाने से यह बदल जाता है।
  • सभी माइग्रेशन को अपडेट करना जो हटाए गए माइग्रेशन पर निर्भर करते हैं बजाय स्क्वैश माइग्रेशन पर निर्भर करते हैं।
  • स्क्वॉश माइग्रेशन के Migration क्लास में replaces विशेषता को हटाते हुए (यह इसी तरह Django बताता है कि यह स्क्वैस्ड माइग्रेशन है)।

ध्यान दें

एक बार जब आप माइग्रेशन स्क्वैश कर लेते हैं, तो आपको उस स्क्वैश माइग्रेशन को फिर से स्क्वैश नहीं करना चाहिए जब तक कि आप इसे पूरी तरह से एक सामान्य माइग्रेशन में परिवर्तित नहीं कर लेते हैं।

मूल्यों का सीरियल करना

माइग्रेशन केवल आपके मॉडल की पुरानी परिभाषाओं वाली पायथन फाइलें हैं - इस प्रकार, उन्हें लिखने के लिए, Django को अपने मॉडल की वर्तमान स्थिति लेनी चाहिए और उन्हें एक फ़ाइल में अनुक्रमित करना चाहिए।

जबकि Django अधिकांश चीजों को क्रमबद्ध कर सकता है, लेकिन कुछ चीजें हैं जो हम सिर्फ एक वैध पायथन प्रतिनिधित्व में अनुक्रमित नहीं कर सकते हैं - कोई पायथन मानक नहीं है कि कैसे मान को वापस कोड में बदल दिया जा सकता है ( repr() केवल मूल मूल्यों के लिए काम करता है, और आयात पथ निर्दिष्ट नहीं करता है)।

Django निम्नलिखित अनुक्रम कर सकते हैं:

  • int , float , bool , str , bytes , None
  • list , set , tuple , dict
  • datetime.date , datetime.time , और datetime.datetime उदाहरण (उन लोगों को शामिल करें जो टाइमज़ोन-जागरूक हैं)
  • decimal.Decimal उदाहरण
  • enum.Enum उदाहरण
  • uuid.UUID उदाहरण
  • functools.partial() और functools.partialmethod उदाहरण हैं, जिनमें functools.partialmethod , और keywords मान हैं।
  • LazyObject इंस्टेंस जो एक क्रमिक मूल्य को लपेटता है।
  • कोई भी Django फ़ील्ड
  • कोई फ़ंक्शन या विधि संदर्भ (जैसे datetime.datetime.today ) (मॉड्यूल के शीर्ष-स्तरीय दायरे में होना चाहिए)
  • क्लास बॉडी के भीतर से इस्तेमाल किए गए अनबाउंड तरीके
  • किसी भी वर्ग का संदर्भ (मॉड्यूल के शीर्ष-स्तरीय दायरे में होना चाहिए)
  • कस्टम deconstruct() विधि के साथ कुछ भी ( नीचे देखें )
Django 2.1 में परिवर्तित:

functools.partialmethod लिए functools.partialmethod समर्थन जोड़ा गया था।

Django अनुक्रमित नहीं कर सकता:

  • नेस्टेड क्लासेस
  • मनमाना वर्ग उदाहरण (जैसे MyClass(4.3, 5.7) )
  • lambdas

एक deconstruct() विधि जोड़ना

आप deconstruct() को कक्षा को एक deconstruct() विधि देकर अपने स्वयं के कस्टम वर्ग उदाहरणों को क्रमबद्ध करने दे सकते हैं। यह कोई तर्क नहीं लेता है, और तीन चीजों (path, args, kwargs) का एक टपल वापस करना चाहिए:

  • path को कक्षा का पायथन path होना चाहिए, जिसमें अंतिम भाग के रूप में शामिल वर्ग का नाम (उदाहरण के लिए, myapp.custom_things.MyClass ) है। यदि आपकी कक्षा किसी मॉड्यूल के शीर्ष स्तर पर उपलब्ध नहीं है, तो यह धारावाहिक नहीं है।
  • अपनी कक्षा ' __init__ ' पद्धति को पास करने के लिए __init__ तर्कों की एक सूची होनी चाहिए। इस सूची में सब कुछ खुद को क्रमबद्ध होना चाहिए।
  • आपकी कक्षा की __init__ पद्धति को पास करने के लिए क्वार्ग्स को खोजशब्द तर्क का एक ताना- kwargs होना चाहिए। हर मूल्य खुद को क्रमबद्ध होना चाहिए।

ध्यान दें

यह वापसी मान कस्टम फ़ील्ड के लिए deconstruct() विधि से अलग है जो चार वस्तुओं का एक टपल लौटाता है।

Django दिए गए तर्कों के साथ आपकी कक्षा की तात्कालिकता के रूप में मूल्य लिखेगा, जिस तरह से यह Django फ़ील्ड्स के संदर्भ लिखता है।

हर बार जब कोई नया माइग्रेशन चलाया जाता है, तो नए माइग्रेशन को रोकने के लिए, आपको सजाया वर्ग में __eq__() विधि भी जोड़ना चाहिए। यह कार्य राज्यों के बीच परिवर्तनों का पता लगाने के लिए Django के प्रवासन ढांचे द्वारा बुलाया जाएगा।

जब तक आपकी कक्षा के कंस्ट्रक्टर के सभी तर्क अपने आप को धारावाहिक करने योग्य नहीं हो जाते, तब तक आप django.utils.deconstruct deconstruct() विधि को जोड़ने के लिए django.utils.deconstruct से django.utils.deconstruct क्लास डेकोरेटर का उपयोग कर सकते हैं:

from django.utils.deconstruct import deconstructible

@deconstructible
class MyCustomClass:

    def __init__(self, foo=1):
        self.foo = foo
        ...

    def __eq__(self, other):
        return self.foo == other.foo

डेकोरेटर तर्क को अपने कंस्ट्रक्टर में अपने रास्ते पर कब्जा करने और संरक्षित करने के लिए जोड़ता है, और फिर उन तर्कों को ठीक से वापस करता है जब डिकॉन्स्ट्रक्ट () कहा जाता है।

कई Django संस्करणों का समर्थन

यदि आप मॉडल के साथ किसी तृतीय-पक्ष ऐप के अनुचर हैं, तो आपको कई Django संस्करणों का समर्थन करने वाले माइग्रेशन को शिप करने की आवश्यकता हो सकती है। इस मामले में, आपको हमेशा सबसे कम Django संस्करण के साथ makemigrations चलाना चाहिए makemigrations आप समर्थन करना चाहते हैं

माइग्रेशन सिस्टम Django के बाकी हिस्सों के समान नीति के अनुसार पीछे की ओर-संगतता बनाए रखेगा, इसलिए Django XY पर उत्पन्न माइग्रेशन फ़ाइलों को Django X.Y + 1 पर अपरिवर्तित चलना चाहिए। माइग्रेशन सिस्टम हालांकि, फॉरवर्ड-संगतता का वादा नहीं करता है। नई सुविधाएँ जोड़ी जा सकती हैं, और Django के नए संस्करणों के साथ उत्पन्न माइग्रेशन फ़ाइलें पुराने संस्करणों पर काम नहीं कर सकती हैं।

यह भी देखें

Operations
स्कीमा ऑपरेशंस API, स्पेशल ऑपरेशंस और अपने खुद के ऑपरेशन्स को लिखना शामिल है।
लेखन का पलायन "कैसे-कैसे"
बताते हैं कि अलग-अलग परिदृश्यों के लिए डेटाबेस माइग्रेशन की संरचना और लेखन कैसे करें जो आप सामना कर सकते हैं।

Original text