दो Django एप्लिकेशन (Django 1.7) के बीच एक मॉडल को कैसे स्थानांतरित करें


133

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

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

हालाँकि, Django 1.7 के कारण और पलायन के समर्थन में बनाया गया, क्या अब ऐसा करने का एक बेहतर तरीका है?


4
आप स्वीकृत उत्तर को बदलने पर विचार कर सकते हैं।
बबकेन वर्दयान

भविष्य में इस पर आने वाले लोगों के लिए: यहाँ Django 3.x, और दृष्टिकोण realpython.com/move-django-model/… पर विस्तृत रूप से काम किया। मेरे पास पुराने ऐप में मॉडल, और नए ऐप में मॉडल के बीच कई विदेशी कुंजियाँ थीं।
प्रदीपसेप

जवाबों:


16

मैं पुराने उत्तर को हटा रहा हूं क्योंकि डेटा हानि हो सकती है। जैसा कि ओज़ान ने उल्लेख किया है , हम प्रत्येक ऐप में 2 माइग्रेशन एक बना सकते हैं। इस पोस्ट के नीचे की टिप्पणियाँ मेरे पुराने उत्तर को संदर्भित करती हैं।

1 ऐप से मॉडल निकालने के लिए पहला माइग्रेशन।

$ python manage.py makemigrations old_app --empty

इन कार्यों को शामिल करने के लिए माइग्रेशन फ़ाइल संपादित करें।

class Migration(migrations.Migration):

    database_operations = [migrations.AlterModelTable('TheModel', 'newapp_themodel')]

    state_operations = [migrations.DeleteModel('TheModel')]

    operations = [
      migrations.SeparateDatabaseAndState(
        database_operations=database_operations,
        state_operations=state_operations)
    ]

दूसरा माइग्रेशन जो पहले माइग्रेशन पर निर्भर करता है और 2 डी ऐप में नई तालिका बनाता है। 2 कोड पर मॉडल कोड को स्थानांतरित करने के बाद

$ python manage.py makemigrations new_app 

और माइग्रेशन फ़ाइल को कुछ इस तरह संपादित करें।

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]

मेरे पास मौजूदा डेटा है और इसमें से बहुत कुछ है जो मैं बस खो नहीं सकता, यह संभवतः इसके साथ करना है?
सैम बकिंघम

@KevinChristopherHenry ने कोड को संशोधित किया। यह मौजूदा डेटा को संरक्षित करता है।
चिल्लरअनंद

@SamBuckingham हां, आप डेटा को खोए बिना माइग्रेट करने के लिए संशोधित कोड के साथ कोशिश कर सकते हैं।
चिल्लरअनंद

2
मुझे लगता है कि यह वास्तव में सबसे अच्छा तरीका होने जा रहा है, सभी लोगों की मदद के लिए धन्यवाद, जो शानदार रहा है।
सैम बकिंघम

1
IMO यह एक गलत समाधान है, पलायन की मूल धारणा यह है कि यदि आप ./manage.py migrateसब कुछ चलाते हैं तो अच्छी स्थिति समाप्त हो जाएगी। मैन्युअल रूप से फ़ेकिंग माइग्रेशन IMO एक गलत तरीका है।
जेबी

341

यह काफी आसानी से उपयोग किया जा सकता है migrations.SeparateDatabaseAndState । असल में, हम एक ऐप के इतिहास से मॉडल को हटाने और इसे दूसरे में बनाने के लिए दो राज्य के संचालन के साथ तालिका का नाम बदलने के लिए एक डेटाबेस ऑपरेशन का उपयोग करते हैं।

पुराने ऐप से निकालें

python manage.py makemigrations old_app --empty

माइग्रेशन में:

class Migration(migrations.Migration):

    dependencies = []

    database_operations = [
        migrations.AlterModelTable('TheModel', 'newapp_themodel')
    ]

    state_operations = [
        migrations.DeleteModel('TheModel')
    ]

    operations = [
        migrations.SeparateDatabaseAndState(
            database_operations=database_operations,
            state_operations=state_operations)
    ]

नए ऐप में जोड़ें

सबसे पहले, मॉडल को नए ऐप के मॉडल-थ्रू कॉपी करें, फिर:

python manage.py makemigrations new_app

यह CreateModelएकमात्र ऑपरेशन के रूप में एक भोले संचालन के साथ एक माइग्रेशन उत्पन्न करेगा । एक SeparateDatabaseAndStateऑपरेशन में लपेटें कि हम तालिका को फिर से बनाने की कोशिश न करें। एक निर्भरता के रूप में पूर्व प्रवास को भी शामिल करें:

class Migration(migrations.Migration):

    dependencies = [
        ('old_app', 'above_migration')
    ]

    state_operations = [
        migrations.CreateModel(
            name='TheModel',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
            ],
            options={
                'db_table': 'newapp_themodel',
            },
            bases=(models.Model,),
        )
    ]

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=state_operations)
    ]

14
वास्तव में अच्छी व्याख्या। यह जवाब होना चाहिए, तालिका का नाम बदलने के साथ आप किसी भी डेटा को खोने से बचते हैं।
रेमीज़ २३:१४

11
यह इसे करने का सबसे अच्छा तरीका है और यह मेरी तुलना में कहीं बेहतर है। मेरे जवाब के शीर्ष पर जोड़ा गया नोट।
चिल्लरानंद

4
मैंने ऐसा किया था, लेकिन जब मैं इसके बाद newapp पर "makemigrations" चलाता हूं, तो यह AlterModelTable माइग्रेशन को इसे किसी को भी नाम नहीं देता है।
डिएगो पोंचियानो

4
इन निर्देशों के आधार पर मेरी समस्या को हल करने का एक तरीका मिला। यदि आपके पास विदेशी कुंजी संदर्भ हैं जो आवश्यक फ़ील्ड हैं तो समस्या अधिक जटिल है। मुझे संदर्भों को स्थानांतरित करने के लिए कुछ कदम जोड़ना पड़ा।
Nostalg.io

14
कई अनुरोधों के कारण, मैंने एक GitHub उदाहरण के साथ FK मॉडल माइग्रेशन पर एक विस्तृत उत्तर बनाया है। stackoverflow.com/questions/30601107/…
Nostalg.io

26

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

आपको 2 और चरणों की आवश्यकता है:

  1. कुछ भी करने से पहले, अपने सभी ForeignKeyलिंकिंग को TheModelबदल दें Integerfield। फिर भागोpython manage.py makemigrations
  2. ओज़ान के चरणों को करने के बाद, अपनी विदेशी कुंजियों को फिर से रूपांतरित करें: के ForeignKey(TheModel)बजाय वापस रख दें IntegerField()। फिर माइग्रेशन फिर से करें ( python manage.py makemigrations)। तब आप माइग्रेट कर सकते हैं और यह काम करना चाहिए ( python manage.py migrate)

आशा करता हूँ की ये काम करेगा। बेशक खराब सुपरराइज से बचने के लिए उत्पादन में प्रयास करने से पहले स्थानीय रूप से इसका परीक्षण करें :)


8
ManyToManyField रिश्तों के बारे में क्या ??
टॉमकॉन्सेल

1
@tomcounsell महान टिप्पणी, मैं केवल पलायन के उद्देश्य के लिए मॉडल के माध्यम से एक विशिष्ट जोड़कर मान सकता हूं। डेटा को छोड़ने के लिए आवश्यक काम का बड़ा सौदा ...
Wtower

चूंकि कई-से-कई संबंध आमतौर पर सिर्फ दो विदेशी कुंजी के साथ एक तालिका है, SQL बिंदु से आप इस उत्तर की चाल को लागू कर सकते हैं। लेकिन केवल Django के माध्यम से इसे प्राप्त करने के लिए, एक दृष्टिकोण जिसके बारे में मैं सोच सकता हूं, वह @ozan उत्तर की तर्ज पर होगा, सिवाय इसके कि पहला कदम MTM संबंध में शामिल तालिकाओं की नकल करना होगा (प्रत्येक ऐप में डुप्स का एक संस्करण) , सभी विदेशी कुंजियों को नए ऐप में माइग्रेट करें, और उसके बाद ही पुराने ऐप में मौजूद डुप्लिकेट को हटाएं। डिस्क्लेमर: मैंने परीक्षण नहीं किया है :)
अरनौद पी।

15

मैंने इसे कैसे किया (पोस्टिंग के साथ, Django == 1.8 पर परीक्षण किया, इसलिए शायद 1.7 भी)

परिस्थिति

app1.YourModel

लेकिन आप चाहते हैं कि यह जाए: app2.YourModel

  1. App1 से app2 से YourModel (कोड) की प्रतिलिपि बनाएँ।
  2. app2.YourModel में इसे जोड़ें:

    Class Meta:
        db_table = 'app1_yourmodel'
  3. $ python manage.py makemigrations app2

  4. एक नया माइग्रेशन (उदा। 0009_auto_something.py) app2 में एक माइग्रेशन के साथ बनाया गया है। CreateModel () स्टेटमेंट, इस स्टेटमेंट को ऐप 2 के शुरुआती माइग्रेशन (जैसे 0001_initial.py) पर ले जाएं (यह हमेशा की तरह ही होगा)। और अब बना हुआ माइग्रेशन = 0009_auto_something.py को हटा दें

  5. जैसे आप अभिनय करते हैं, जैसे app2.YourModel हमेशा से रहा है, अब अपने माइग्रेशन से app1.YourModel के अस्तित्व को हटा दें। अर्थ: CreateModel स्टेटमेंट और उसके बाद आपके द्वारा उपयोग किए जाने वाले प्रत्येक समायोजन या डेटा माइग्रेशन पर टिप्पणी करें।

  6. और हां, app1.YourModel के लिए हर संदर्भ को अपने प्रोजेक्ट के माध्यम से app2.YourModel में बदलना होगा। इसके अलावा, यह न भूलें कि app1.YourModel में सभी संभावित विदेशी कुंजी को बदलकर app2.YourModel में बदलना होगा

  7. अब यदि आप $ python manage.py माइग्रेट करते हैं, तो कुछ भी नहीं बदला है, जब आप $ python manage.py makemigrations भी करते हैं, तो कुछ भी नया नहीं पाया गया है।

  8. अब फिनिशिंग टच: app2.YourModel से क्लास मेटा हटा दें और $ python manage.py makemigrations app2 && python manage.py app2 माइग्रेट करें (यदि आप इस माइग्रेशन को देखेंगे तो आप इस तरह दिखेंगे :)

        migrations.AlterModelTable(
        name='yourmodel',
        table=None,
    ),

तालिका = कोई नहीं, इसका अर्थ है कि यह डिफ़ॉल्ट तालिका-नाम लेगा, जो इस स्थिति में app2_yourmodel होगा।

  1. किया गया, डेटा सहेजा गया।

पीएस माइग्रेशन के दौरान यह देखेगा कि content_type app1.yourmodel हटा दिया गया है और इसे हटाया जा सकता है। आप इसके लिए हां कह सकते हैं, लेकिन केवल तभी जब आप इसका उपयोग न करें। यदि आप इस पर निर्भर करते हैं कि उस सामग्री-प्रकार के लिए FKs बरकरार है, तो इसका उत्तर हां या नहीं में दें, लेकिन उस समय में db को मैन्युअल रूप से जाएं, और contentype app2.yourmodel को हटा दें, और contenttype app1 का नाम बदलें। yourmodel to app2.yourmodel, और फिर उत्तर न देकर जारी रखें।


3
जबकि यह समाधान निश्चित रूप से @ ओज़न की तुलना में "हैकर" है और इसे निश्चित रूप से अधिक संपादन की आवश्यकता है, इसने मेरे लिए अच्छी तरह से काम किया (और माइग्रेशन संपादित करना ठीक है - उन्हें डॉक्स के अनुसार संपादन योग्य माना जाता है)।
pgcd

1
संभवतः app_label = 'app1'मेटा विकल्प का भी उपयोग करें ।
वेटॉवर

प्रतिभाशाली! फॉरेनके रिश्तों के लिए इसने मेरे लिए बहुत काम किया। मुझे लगता है कि यह भी कईTMMany क्षेत्रों के लिए भी काम करेगा।
बबकेन वर्दयान

मैंने आपके कदमों का पालन किया, लेकिन app1 से संबंधित कुछ मॉडल में फ़ील्ड में फॉरेन की से बना होता है, जिसके साथ मॉडल (myModel) के लिए पुनरावर्ती संबंध होता है। जैसा field1 = models.ForeignKey('app1.myModel').जब मैं विस्थापित, मैं एक ValueError करते हुए कहा कि मिलfield1 was declared with a lazy reference to 'app1.myModel' but app 'app1' doesn't provide model 'MyModel'
Deesha

12

मुझे नर्वस हैंड-कोडिंग माइग्रेशन मिलता है (जैसा कि ओज़ान के जवाब के लिए आवश्यक है ) इसलिए निम्न ओज़ान और माइकल की रणनीतियों को जोड़ती है ताकि आवश्यक हैंड-कोडिंग की मात्रा कम हो सके:

  1. किसी भी मॉडल को स्थानांतरित करने से पहले, सुनिश्चित करें कि आप दौड़कर एक साफ आधार रेखा के साथ काम कर रहे हैं makemigrations
  2. से मॉडल के लिए कोड को इस app1के लिएapp2
  3. जैसा कि @Michael द्वारा सुझाया गया है, हम db_table"नया" मॉडल पर मेटा विकल्प का उपयोग करते हुए पुराने डेटाबेस टेबल पर नए मॉडल को इंगित करते हैं :

    class Meta:
        db_table = 'app1_yourmodel'
  4. भागो makemigrations। यह उत्पन्न होगा CreateModelमें app2और DeleteModelमें app1। तकनीकी रूप से, ये माइग्रेशन ठीक उसी तालिका को संदर्भित करते हैं और हटा देंगे (सभी डेटा सहित) और तालिका को फिर से बनाएँ।

  5. वास्तव में, हम मेज पर कुछ भी करने के लिए (या आवश्यकता) नहीं चाहते हैं। हमें केवल यह विश्वास करने की आवश्यकता है कि परिवर्तन किया गया है। @ ओज़ान के जवाब के अनुसार, state_operationsझंडा SeparateDatabaseAndStateऐसा करता है। इसलिए हम सभी को लपेट migrationsप्रविष्टियों दोनों माइग्रेशन फाइलों में साथ SeparateDatabaseAndState(state_operations=[...])। उदाहरण के लिए,

    operations = [
        ...
        migrations.DeleteModel(
            name='YourModel',
        ),
        ...
    ]

    हो जाता है

    operations = [
        migrations.SeparateDatabaseAndState(state_operations=[
            ...
            migrations.DeleteModel(
                name='YourModel',
            ),
            ...
        ])
    ]
  6. आपको यह सुनिश्चित करने की भी ज़रूरत है कि नया "वर्चुअल" CreateModelमाइग्रेशन किसी भी माइग्रेशन पर निर्भर करता है जो वास्तव में मूल तालिका को बनाया या बदल दिया गया है । उदाहरण के लिए, यदि आपके नए माइग्रेशन app2.migrations.0004_auto_<date>(के लिए Create) और app1.migrations.0007_auto_<date>( Delete) के लिए हैं, तो सबसे आसान काम है:

    • app1.migrations.0007_auto_<date>इसकी app1निर्भरता (जैसे ('app1', '0006...'),) खोलें और कॉपी करें । यह "तुरंत पूर्व" माइग्रेशन है app1और इसमें सभी वास्तविक मॉडल बिल्डिंग तर्क पर निर्भरता शामिल होनी चाहिए।
    • app2.migrations.0004_auto_<date>उस निर्भरता को खोलें जिसे आपने उसकी dependenciesसूची में कॉपी किया है ।

यदि आप ForeignKeyजिस मॉडल के साथ आगे बढ़ रहे हैं, उससे आपके संबंध हैं, तो उपरोक्त कार्य नहीं हो सकता है। ऐसा होता है क्योंकि:

  • ForeignKeyपरिवर्तनों के लिए निर्भरताएँ स्वचालित रूप से नहीं बनती हैं
  • हम ForeignKeyपरिवर्तनों को लपेटना नहीं चाहते हैं, state_operationsइसलिए हमें यह सुनिश्चित करने की आवश्यकता है कि वे तालिका संचालन से अलग हैं।

नोट: Django 2.2 ने एक चेतावनी जोड़ी ( models.E028) जो इस पद्धति को तोड़ती है। आप इसके साथ काम करने में सक्षम हो सकते हैं managed=Falseलेकिन मैंने इसका परीक्षण नहीं किया है।

ऑपरेशन का "न्यूनतम" सेट स्थिति के आधार पर भिन्न होता है, लेकिन निम्नलिखित प्रक्रिया को अधिकांश / सभी ForeignKeyमाइग्रेशन के लिए काम करना चाहिए :

  1. कॉपी से मॉडल app1के लिए app2, सेट db_table, लेकिन किसी भी FK संदर्भ में बदलाव नहीं।
  2. makemigrationsसभी app2माइग्रेशन चलाएं और लपेटें state_operations(ऊपर देखें)
    • उपरोक्त के रूप में, app2 CreateTableनवीनतम app1माइग्रेशन में एक निर्भरता जोड़ें
  3. नए मॉडल के सभी एफके संदर्भों को इंगित करें। यदि आप स्ट्रिंग संदर्भों का उपयोग नहीं कर रहे हैं, तो पुराने मॉडल को नीचे की ओर ले जाएं models.py(इसे हटाएं नहीं) ताकि यह आयातित वर्ग के साथ प्रतिस्पर्धा न करे।
  4. भागो, makemigrationsलेकिन state_operations(FK परिवर्तन वास्तव में होना चाहिए) में कुछ भी लपेटो नहीं । सभी में एक निर्भरता जोड़ें ForeignKeyमाइग्रेशन (यानी AlterFieldकरने के लिए) CreateTableमें प्रवास app2(आपको अगले चरण के लिए इस सूची की आवश्यकता होगी तो उन पर नज़र रखने के लिए)। उदाहरण के लिए:

    • उस माइग्रेशन का पता लगाएं, जिसमें CreateModelउदा शामिल है app2.migrations.0002_auto_<date>और उस माइग्रेशन का नाम कॉपी करें।
    • उन सभी माइग्रेशन का पता लगाएं, जो उस मॉडल के लिए एक विदेशी है (जैसे app2.YourModelमाइग्रेशन खोजने के लिए खोज करके :

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
          ]
      
          operations = [
              migrations.AlterField(
                  model_name='relatedmodel',
                  name='fieldname',
                  field=models.ForeignKey(... to='app2.YourModel'),
              ),
          ]
    • CreateModelमाइग्रेशन को एक निर्भरता के रूप में जोड़ें :

      class Migration(migrations.Migration):
      
          dependencies = [
              ('otherapp', '0001_initial'),
              ('app2', '0002_auto_<date>'),
          ]  
  5. से मॉडल निकालें app1

  6. माइग्रेशन को चलाएं makemigrationsऔर लपेटें । app1state_operations
    • पिछले चरण से सभी ForeignKeyमाइग्रेशन (यानी AlterField) में निर्भरता जोड़ें (इसमें माइग्रेशन शामिल हो सकते हैं ) app1और app2
    • जब मैंने ये माइग्रेशन बनाया, तो DeleteTableपहले से ही AlterFieldमाइग्रेशन पर निर्भर था इसलिए मुझे इसे (यानी Alterपहले Delete) मैन्युअल रूप से लागू करने की आवश्यकता नहीं थी ।

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

मैं अपने (मेटा विकल्पों और तालिका नामों) के बाद सफाई करना चाहता था, इसलिए मैंने निम्नलिखित प्रक्रिया (@ मिचेल से) का उपयोग किया:

  1. db_tableमेटा प्रविष्टि को निकालें
  2. makemigrationsडेटाबेस का नाम बदलने के लिए फिर से चलाएँ
  3. इस अंतिम माइग्रेशन को संपादित करें और सुनिश्चित करें कि यह DeleteTableमाइग्रेशन पर निर्भर करता है । ऐसा नहीं लगता कि यह आवश्यक Deleteहोना चाहिए क्योंकि विशुद्ध रूप से तार्किक होना चाहिए, लेकिन app1_yourmodelअगर मैं नहीं करता हूं तो मैं त्रुटियों में भाग गया हूं (जैसे मौजूद नहीं है)।

यह पूरी तरह से काम किया, धन्यवाद! मुझे नहीं लगता कि पिछले माइग्रेशन मामलों को संपादित करना, क्योंकि यह वैसे भी निर्भरता के पेड़ के नीचे है।
जेम्स मीकिन

1
अच्छा उत्तर! मुझे लगता है कि आपको माइग्रेशन के लिए एक समापन कोष्ठक जोड़ने की आवश्यकता है। SeparateDatabaseAndState, सही है?
atm

इसने मेरे लिए काम किया। मैंने @JamesMeakin की तरह अंतिम माइग्रेशन (चरण 3, संपूर्ण उत्तर की अंतिम पंक्ति) को भी संपादित नहीं किया था और यह अभी भी ठीक काम किया है
मेगावट

दूसरे परिदृश्य में, एफके के साथ एक, दूसरा कदम मेरे लिए एक त्रुटि के साथ विफल रहा जो समझ में आता है:table_name: (models.E028) db_table 'table_name' is used by multiple models: app1.Model, app2.Model.
मिहाई ज़म्फिर

मैंने एक दो बार प्रक्रिया का उपयोग किया है। यदि आप 2.2 ( docs.djangoproject.com/en/2.2/ref/checks ) और 2.1 ( docs.djangoproject.com/en/2.1/ref/checks ) के लिए दस्तावेज़ की तुलना करते हैं , तो आप देख सकते हैं कि इसे 2.2 में जोड़ा गया था। यह साथ काम करने के लिए संभव हो सकता है managed=Falseलेकिन मैं जाँच करने के लिए किसी जगह पर नहीं हूँ।
मिट्टी का मटका

1

यदि डेटा बड़ा या बहुत जटिल नहीं है, लेकिन फिर भी बनाए रखने के लिए महत्वपूर्ण है, तो एक और हैकई विकल्प:

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

1

Https://stackoverflow.com/a/47392970/8971048 पर मेरे जवाब से कॉपी किया गया

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

इस उदाहरण में मैं 'MyModel' को old_app से myapp पर भेज रहा हूं।

class MigrateOrCreateTable(migrations.CreateModel):
    def __init__(self, source_table, dst_table, *args, **kwargs):
        super(MigrateOrCreateTable, self).__init__(*args, **kwargs)
        self.source_table = source_table
        self.dst_table = dst_table

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        table_exists = self.source_table in schema_editor.connection.introspection.table_names()
        if table_exists:
            with schema_editor.connection.cursor() as cursor:
                cursor.execute("RENAME TABLE {} TO {};".format(self.source_table, self.dst_table))
        else:
            return super(MigrateOrCreateTable, self).database_forwards(app_label, schema_editor, from_state, to_state)


class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0002_some_migration'),
    ]

    operations = [
        MigrateOrCreateTable(
            source_table='old_app_mymodel',
            dst_table='myapp_mymodel',
            name='MyModel',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=18))
            ],
        ),
    ]

कृपया एक से अधिक प्रश्नों के उत्तर न जोड़ें। सर्वश्रेष्ठ का उत्तर दें और बाकी को डुप्लिकेट के रूप में चिह्नित करें। देखें कि क्या कई सवालों के डुप्लीकेट उत्तर को जोड़ना स्वीकार्य है?
फ्रीबर्ग

0

यह मोटे तौर पर परीक्षण किया है, तो अपने DB बैकअप करने के लिए मत भूलना !!!

उदाहरण के लिए, वहाँ दो क्षुधा हैं: src_appऔर dst_app, हम मॉडल ले जाना चाहते हैं MoveMeसे src_appकरने के लिए dst_app

दोनों ऐप्स के लिए खाली माइग्रेशन बनाएं:

python manage.py makemigrations --empty src_app
python manage.py makemigrations --empty dst_app

मान लेते हैं, कि नए माइग्रेशन हैं XXX1_src_app_newऔर XXX1_dst_app_new, प्रीवियस शीर्ष माइग्रेशन हैं XXX0_src_app_oldऔर XXX0_dst_app_old

MoveMeमॉडल के लिए तालिका का नाम बदलने और ProjectState में अपने app_label का नाम बदलने के लिए एक ऑपरेशन जोड़ें XXX1_dst_app_newXXX0_src_app_oldप्रवासन पर निर्भरता जोड़ना न भूलें । परिणामी XXX1_dst_app_newप्रवास है:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

# this operations is almost the same as RenameModel
# https://github.com/django/django/blob/1.7/django/db/migrations/operations/models.py#L104
class MoveModelFromOtherApp(migrations.operations.base.Operation):

    def __init__(self, name, old_app_label):
        self.name = name
        self.old_app_label = old_app_label

    def state_forwards(self, app_label, state):

        # Get all of the related objects we need to repoint
        apps = state.render(skip_cache=True)
        model = apps.get_model(self.old_app_label, self.name)
        related_objects = model._meta.get_all_related_objects()
        related_m2m_objects = model._meta.get_all_related_many_to_many_objects()
        # Rename the model
        state.models[app_label, self.name.lower()] = state.models.pop(
            (self.old_app_label, self.name.lower())
        )
        state.models[app_label, self.name.lower()].app_label = app_label
        for model_state in state.models.values():
            try:
                i = model_state.bases.index("%s.%s" % (self.old_app_label, self.name.lower()))
                model_state.bases = model_state.bases[:i] + ("%s.%s" % (app_label, self.name.lower()),) + model_state.bases[i+1:]
            except ValueError:
                pass
        # Repoint the FKs and M2Ms pointing to us
        for related_object in (related_objects + related_m2m_objects):
            # Use the new related key for self referential related objects.
            if related_object.model == model:
                related_key = (app_label, self.name.lower())
            else:
                related_key = (
                    related_object.model._meta.app_label,
                    related_object.model._meta.object_name.lower(),
                )
            new_fields = []
            for name, field in state.models[related_key].fields:
                if name == related_object.field.name:
                    field = field.clone()
                    field.rel.to = "%s.%s" % (app_label, self.name)
                new_fields.append((name, field))
            state.models[related_key].fields = new_fields

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        old_apps = from_state.render()
        new_apps = to_state.render()
        old_model = old_apps.get_model(self.old_app_label, self.name)
        new_model = new_apps.get_model(app_label, self.name)
        if self.allowed_to_migrate(schema_editor.connection.alias, new_model):
            # Move the main table
            schema_editor.alter_db_table(
                new_model,
                old_model._meta.db_table,
                new_model._meta.db_table,
            )
            # Alter the fields pointing to us
            related_objects = old_model._meta.get_all_related_objects()
            related_m2m_objects = old_model._meta.get_all_related_many_to_many_objects()
            for related_object in (related_objects + related_m2m_objects):
                if related_object.model == old_model:
                    model = new_model
                    related_key = (app_label, self.name.lower())
                else:
                    model = related_object.model
                    related_key = (
                        related_object.model._meta.app_label,
                        related_object.model._meta.object_name.lower(),
                    )
                to_field = new_apps.get_model(
                    *related_key
                )._meta.get_field_by_name(related_object.field.name)[0]
                schema_editor.alter_field(
                    model,
                    related_object.field,
                    to_field,
                )

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        self.old_app_label, app_label = app_label, self.old_app_label
        self.database_forwards(app_label, schema_editor, from_state, to_state)
        app_label, self.old_app_label = self.old_app_label, app_label

    def describe(self):
        return "Move %s from %s" % (self.name, self.old_app_label)


class Migration(migrations.Migration):

    dependencies = [
       ('dst_app', 'XXX0_dst_app_old'),
       ('src_app', 'XXX0_src_app_old'),
    ]

    operations = [
        MoveModelFromOtherApp('MoveMe', 'src_app'),
    ]

पर निर्भरता जोड़े XXX1_dst_app_newके लिए XXX1_src_app_newXXX1_src_app_newनो-ऑप माइग्रेशन है जिसे यह सुनिश्चित करने की आवश्यकता है कि भविष्य के src_appमाइग्रेशन के बाद निष्पादित किया जाएगा XXX1_dst_app_new

हटो MoveMeसे src_app/models.pyकरने के लिए dst_app/models.py। फिर भागो:

python manage.py migrate

बस इतना ही!


ध्यान दें कि यह कोड शायद केवल django 1.7 के लिए उपयोगी है। यह django 2.0 में कोशिश करने से काम नहीं चलेगा। इसका मतलब यह भी है कि चलती मॉडल के लिए इस तंत्र का उपयोग करने से आपके django संस्करण को अपग्रेड करने के लिए रखरखाव ओवरहेड जुड़ जाता है।
पॉल 'टी हाउट

0

आप निम्नलिखित (अप्राप्त) आज़मा सकते हैं:

  1. से मॉडल को स्थानांतरित करें src_app करने के लिएdest_app
  2. पलायन dest_app; सुनिश्चित करें कि स्कीमा माइग्रेशन नवीनतम src_appमाइग्रेशन पर निर्भर करता है ( https://docs.djangoproject.com/en/dev/topics/migrations/#migration-files )
  3. इसमें एक डेटा माइग्रेशन जोड़ें dest_app , जो सभी डेटा की प्रतिलिपि बनाता हैsrc_app
  4. पलायन src_app; सुनिश्चित करें कि स्कीमा माइग्रेशन नवीनतम (डेटा) माइग्रेशन पर निर्भर करता हैdest_app - अर्थात: चरण 3 का माइग्रेशन

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


0

आओ हम कहते हैं कि आप मॉडल TheModel को app_a से app_b पर ले जा रहे हैं।

एक वैकल्पिक समाधान मौजूदा माइग्रेशन को हाथ से बदलना है। विचार यह है कि हर बार जब आप एक ऑपरेशन को app_a के माइग्रेशन में TheModel को बदलते हुए देखते हैं, तो आप उस ऑपरेशन को app_b के प्रारंभिक माइग्रेशन के अंत में कॉपी कर लेते हैं। और हर बार जब आप app_a के माइग्रेशन में एक संदर्भ 'app_a.TheModel' देखते हैं, तो आप इसे 'app_b.TheModel' में बदलते हैं।

मैंने यह एक मौजूदा परियोजना के लिए किया था, जहां मैं एक निश्चित मॉडल को एक पुन: प्रयोज्य एप्लिकेशन को निकालना चाहता था। प्रक्रिया सुचारू रूप से चली। मुझे लगता है कि अगर app_b से app_a तक संदर्भ होते तो चीजें बहुत कठिन होतीं। इसके अलावा, मैंने अपने मॉडल के लिए मैन्युअल रूप से परिभाषित Meta.db_table की मदद की थी जो शायद मदद कर सकता है।

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


0
  1. पुराने मॉडल के नाम बदलकर 'model_name_old' करें
  2. makemigrations
  3. संबंधित मॉडल पर समान रिश्तों के साथ 'model_name_new' नाम के नए मॉडल बनाएं (जैसे। उपयोगकर्ता मॉडल में अब user.blog_old और user.blog_new है)
  4. makemigrations
  5. एक कस्टम माइग्रेशन लिखें जो सभी डेटा को नए मॉडल टेबल पर माइग्रेट करता है
  6. माइग्रेशन चलाने से पहले और बाद में नई डीबी प्रतियों के साथ बैकअप की तुलना करके इन पलायनों से नरक का परीक्षण करें
  7. जब सभी संतोषजनक हो, तो पुराने मॉडल हटा दें
  8. makemigrations
  9. नए मॉडल को सही नाम 'model_name_new' -> 'model_name' में बदलें
  10. चरणबद्ध सर्वर पर माइग्रेशन के पूरे स्लीव का परीक्षण करें
  11. उपयोगकर्ताओं के हस्तक्षेप के बिना सभी माइग्रेशन चलाने के लिए कुछ मिनटों के लिए अपनी उत्पादन साइट को नीचे ले जाएं

प्रत्येक मॉडल के लिए इसे व्यक्तिगत रूप से करें जिसे स्थानांतरित करने की आवश्यकता है। मैं ऐसा करने का सुझाव नहीं दूंगा जो अन्य उत्तर पूर्णांक और विदेशी कुंजियों में बदलकर कहता है। एक मौका है कि नई विदेशी कुंजी अलग होगी और माइग्रेशन के बाद पंक्तियों की अलग-अलग आईडी हो सकती है और मैं कोई जोखिम नहीं उठाना चाहता था विदेशी चाबियों को वापस स्विच करते समय आईडी बेमेल।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.