मैं एक django ऐप से एक मॉडल में और एक नए मॉडल में माइग्रेट कैसे करूं?




migration django-south (5)

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

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


दक्षिण का उपयोग कैसे माइग्रेट करें।

आइए कहें कि हमें दो ऐप्स मिल गए हैं: सामान्य और विशिष्ट:

myproject/
|-- common
|   |-- migrations
|   |   |-- 0001_initial.py
|   |   `-- 0002_create_cat.py
|   `-- models.py
`-- specific
    |-- migrations
    |   |-- 0001_initial.py
    |   `-- 0002_create_dog.py
    `-- models.py

अब हम मॉडल सामान्य.models.cat को विशिष्ट ऐप में ले जाना चाहते हैं (ठीक से विशिष्ट.models.cat)। पहले स्रोत कोड में परिवर्तन करें और फिर चलाएं:

$ python manage.py schemamigration specific create_cat --auto
 + Added model 'specific.cat'
$ python manage.py schemamigration common drop_cat --auto
 - Deleted model 'common.cat'

myproject/
|-- common
|   |-- migrations
|   |   |-- 0001_initial.py
|   |   |-- 0002_create_cat.py
|   |   `-- 0003_drop_cat.py
|   `-- models.py
`-- specific
    |-- migrations
    |   |-- 0001_initial.py
    |   |-- 0002_create_dog.py
    |   `-- 0003_create_cat.py
    `-- models.py

अब हमें माइग्रेशन फाइलों को संपादित करने की आवश्यकता है:

#0003_create_cat: replace existing forward and backward code
#to use just one sentence:

def forwards(self, orm):
    db.rename_table('common_cat', 'specific_cat') 

    if not db.dry_run:
        # For permissions to work properly after migrating
        orm['contenttypes.contenttype'].objects.filter(
            app_label='common',
            model='cat',
        ).update(app_label='specific')

def backwards(self, orm):
    db.rename_table('specific_cat', 'common_cat')

    if not db.dry_run:
        # For permissions to work properly after migrating
        orm['contenttypes.contenttype'].objects.filter(
            app_label='specific',
            model='cat',
        ).update(app_label='common')
#0003_drop_cat:replace existing forward and backward code
#to use just one sentence; add dependency:

depends_on = (
    ('specific', '0003_create_cat'),
)
def forwards(self, orm):
    pass
def backwards(self, orm):
    pass

अब दोनों ऐप्स माइग्रेशन परिवर्तन के बारे में जानते हैं और जीवन थोड़ा कम बेकार है :-) माइग्रेशन के बीच इस संबंध को स्थापित करना सफलता की कुंजी है। अब यदि आप करते हैं:

python manage.py migrate common
 > specific: 0003_create_cat
 > common: 0003_drop_cat

माइग्रेशन दोनों करेंगे, और

python manage.py migrate specific 0002_create_dog
 < common: 0003_drop_cat
 < specific: 0003_create_cat

चीजों को नीचे माइग्रेट करेगा।

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


के answer पर निर्माण करने के लिए, स्थितियों को और अधिक जटिल हैं और थोड़ा अलग तरीके से संभाला जाना चाहिए।

(निम्नलिखित उदाहरण वर्तमान उत्तर में निर्दिष्ट common और specific ऐप्स पर बनाता है)।

# common/models.py

class Cat(models.Model):
    # ...

class Toy(models.Model):
    belongs_to = models.ForeignKey(Cat)
    # ...

फिर बदल जाएगा

# common/models.py

from specific.models import Cat

class Toy(models.Model):
    belongs_to = models.ForeignKey(Cat)
    # ...

# specific/models.py

class Cat(models.Model):
    # ...

चल रहा है

./manage.py schemamigration common --auto
./manage.py schemamigration specific --auto # or --initial

निम्नलिखित माइग्रेशन उत्पन्न करेंगे (मैं जानबूझकर Django ContentType परिवर्तनों को अनदेखा कर रहा हूं- इसे पहले कैसे संदर्भित करने के लिए संदर्भित उत्तर देखें):

# common/migrations/0009_auto__del_cat.py

class Migration(SchemaMigration):
    def forwards(self, orm):
        db.delete_table('common_cat')
        db.alter_column('common_toy', 'belongs_to_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['specific.Cat']))

    def backwards(self, orm):
        db.create_table('common_cat', (
            # ...
        ))
        db.alter_column('common_toy', 'belongs_to_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['common.Cat']))

# specific/migrations/0004_auto__add_cat.py

class Migration(SchemaMigration):
    def forwards(self, orm):
        db.create_table('specific_cat', (
            # ...
        ))

    def backwards(self, orm):
        db.delete_table('specific_cat')

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

# common/migrations/0009_auto__del_cat.py

class Migration(SchemaMigration):

    depends_on = (
        ('specific', '0004_auto__add_cat'),
    )

    def forwards(self, orm):
        db.alter_column('common_toy', 'belongs_to_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['specific.Cat']))

    def backwards(self, orm):
        db.rename_table('specific_cat', 'common_cat')
        db.alter_column('common_toy', 'belongs_to_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['common.Cat']))

# specific/migrations/0004_auto__add_cat.py

class Migration(SchemaMigration):
    def forwards(self, orm):
        db.rename_table('common_cat', 'specific_cat')

    def backwards(self, orm):
        pass

दक्षिण प्रलेखन के अनुसार , depends_on यह सुनिश्चित करेगा कि 0004_auto__add_cat से आगे 0009_auto__del_cat समय आगे 0009_auto__del_cat लेकिन पीछे की ओर माइग्रेट करते समय विपरीत क्रम में । यदि हमने specific रोलबैक में db.rename_table('specific_cat', 'common_cat') रोलबैक माइग्रेट करने की कोशिश करते समय common रोलबैक विफल हो जाएगा क्योंकि तालिका संदर्भित तालिका मौजूद नहीं होगी।

उम्मीद है कि यह मौजूदा समाधानों की तुलना में "असली दुनिया" स्थिति के करीब है और किसी को यह सहायक मिलेगा। चीयर्स!


तो ऊपर @Potr से मूल प्रतिक्रिया का उपयोग दक्षिण 0.8.1 और Django 1.5.1 पर मेरे लिए काम नहीं किया। मैं उम्मीद कर रहा हूं कि यह मेरे लिए नीचे काम करता है कि यह दूसरों के लिए सहायक है।

from south.db import db
from south.v2 import SchemaMigration
from django.db import models

class Migration(SchemaMigration):

    def forwards(self, orm):
        db.rename_table('common_cat', 'specific_cat') 

        if not db.dry_run:
             db.execute(
                "update django_content_type set app_label = 'specific' where "
                " app_label = 'common' and model = 'cat';")

    def backwards(self, orm):
        db.rename_table('specific_cat', 'common_cat')
            db.execute(
                "update django_content_type set app_label = 'common' where "
                " app_label = 'specific' and model = 'cat';")

पोटर के उत्कृष्ट समाधान के लिए यहां एक और फिक्स है। निम्नलिखित को विशिष्ट / 0003_create_cat में जोड़ें

depends_on = (
    ('common', '0002_create_cat'),
)

जब तक यह निर्भरता सेट नहीं की जाती है, तब तक दक्षिण गारंटी नहीं देगा कि common_cat तालिका उस समय मौजूद होती है जब विशिष्ट / 0003_create_cat चलाया जाता है, django.db.utils को फेंक देता है django.db.utils.OperationalError: no such table: common_cat आप पर django.db.utils.OperationalError: no such table: common_cat त्रुटि।

जब तक निर्भरता स्पष्ट रूप से सेट नहीं होती है तब तक दक्षिण लेक्सिकोोग्राफिक क्रम में माइग्रेशन चलाता है। चूंकि common specific होने से पहले आता है, इसलिए सभी common माइग्रेशन टेबल नामकरण से पहले चलाए जाएंगे, इसलिए शायद यह पोटर द्वारा दिखाए गए मूल उदाहरण में पुन: उत्पन्न नहीं होगा। लेकिन अगर आप app1 लिए common नाम बदलते हैं और app1 लिए specific हैं app1 आप इस समस्या में भाग लेंगे।


मॉडल बहुत कसकर ऐप्स के साथ मिलकर नहीं हैं, इसलिए चलना काफी सरल है। Django डेटाबेस तालिका के नाम पर ऐप नाम का उपयोग करता है, इसलिए यदि आप अपना ऐप ले जाना चाहते हैं तो आप या तो SQL ALTER TABLE db_table कथन के माध्यम से डेटाबेस तालिका का नाम बदल सकते हैं, या यहां तक ​​कि सरल - बस अपने मॉडल के Meta क्लास में db_table पैरामीटर का उपयोग करें पुराने नाम का संदर्भ लें।

यदि आपने अब तक अपने कोड में app_label या जेनेरिक रिलेशनशिप का इस्तेमाल किया है, तो संभवतः आप उस मॉडल पर इंगित app_label प्रकार के app_label का नाम बदलना app_label जो मौजूदा चल रहा है।

बेशक, यदि आपके पास सुरक्षित रखने के लिए कोई डेटा नहीं है, तो सबसे आसान काम डेटाबेस टेबल को पूरी तरह से ./manage.py syncdb और ./manage.py syncdb फिर से चलाने के लिए करना है।





django-south