python - मॉडल और रिलेशनशिप फ़ील्ड का नाम बदलने के लिए Django माइग्रेशन रणनीति




django-migrations (9)

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

आइए मान लें कि myapp नामक एक Django ऐप के भीतर मैं निम्नलिखित मॉडलों के साथ शुरू करता हूं:

class Foo(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_ridonkulous = models.BooleanField()

मैं Foo मॉडल का नाम बदलना चाहता हूं क्योंकि नाम वास्तव में समझ में नहीं आता है और कोड में भ्रम पैदा कर रहा है, और Bar एक बहुत स्पष्ट नाम के लिए तैयार होगा।

Django विकास प्रलेखन में मैंने जो पढ़ा है, उससे मैं निम्नलिखित माइग्रेशन रणनीति मान रहा हूं:

चरण 1

models.py संशोधित करें:

class Bar(models.Model):  # <-- changed model name
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    foo = models.ForeignKey(Bar)  # <-- changed relation, but not field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Bar)  # <-- changed relation, but not field name
    is_ridonkulous = models.BooleanField()

ध्यान दें कि foo लिए अन्य AnotherModel फ़ील्ड नाम बदल नहीं है, लेकिन संबंध Bar मॉडल में अपडेट किया गया है। मेरा तर्क यह है कि मुझे एक बार में बहुत ज्यादा बदलाव नहीं करना चाहिए और यदि मैंने इस क्षेत्र का नाम bar बदल दिया है तो मुझे उस कॉलम में डेटा खोने का जोखिम होगा।

चरण 2

एक खाली माइग्रेशन बनाएं:

python manage.py makemigrations --empty myapp

चरण 3

संचालन सूची में RenameModel ऑपरेशन जोड़ने के लिए चरण 2 में बनाई गई माइग्रेशन फ़ाइल में Migration क्लास को संपादित करें:

class Migration(migrations.Migration):

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

    operations = [
        migrations.RenameModel('Foo', 'Bar')
    ]

चरण 4

माइग्रेशन लागू करें:

python manage.py migrate

चरण 5

models.py में संबंधित फ़ील्ड नाम संपादित करें:

class Bar(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_ridonkulous = models.BooleanField()

चरण 6

एक और खाली माइग्रेशन बनाएं:

python manage.py makemigrations --empty myapp

चरण 7

संचालन सूची में किसी भी संबंधित फ़ील्ड नामों के लिए RenameField ऑपरेशन जोड़ने के लिए चरण 6 में बनाई गई माइग्रेशन फ़ाइल में Migration क्लास संपादित करें:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0002_rename_fields'),  # <-- is this okay?
    ]

    operations = [
        migrations.RenameField('AnotherModel', 'foo', 'bar'),
        migrations.RenameField('YetAnotherModel', 'foo', 'bar')
    ]

चरण 8

दूसरा प्रवास लागू करें:

python manage.py migrate

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

इसके अलावा, यह बहुत सारे कदमों की तरह लगता है। क्या प्रवासन परिचालन किसी तरह से घुलनशील हो सकता है?

धन्यवाद!


Answers

तो जब मैंने यह कोशिश की, ऐसा लगता है कि आप चरण 3 - 7 को संयोजित कर सकते हैं:

class Migration(migrations.Migration):

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

    operations = [
        migrations.RenameModel('Foo', 'Bar'),
        migrations.RenameField('AnotherModel', 'foo', 'bar'),
        migrations.RenameField('YetAnotherModel', 'foo', 'bar')
    ]

यदि आप नामों को अपडेट नहीं करते हैं, तो आपको कुछ त्रुटियां मिल सकती हैं जैसे admin.py और यहां तक ​​कि पुरानी माइग्रेशन फ़ाइलें (!)।

अद्यतन : जैसा कि ceasaro का उल्लेख है, डीजेंगो के नए संस्करण आमतौर पर पता लगाने और पूछने में सक्षम होते हैं कि मॉडल का नाम बदल दिया गया है या नहीं। तो पहले manage.py makemigrations और फिर माइग्रेशन फ़ाइल की जांच करें।


मुझे समस्या का भी सामना करना पड़ा क्योंकि v.thorey ने वर्णन किया और पाया कि उसका दृष्टिकोण बहुत उपयोगी है लेकिन कम चरणों में घिरा हुआ हो सकता है जो वास्तव में चरण 5 से 8 तक है क्योंकि फिवर चरण 1 से 4 के बिना वर्णित है, सिवाय इसके कि चरण 7 को मेरे रूप में बदला जाना चाहिए चरण 3 के नीचे। समग्र चरण निम्नानुसार हैं:

चरण 1: models.py में संबंधित फ़ील्ड नाम संपादित करें

class Bar(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)


class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar)  # <-- changed field name
    is_ridonkulous = models.BooleanField()

चरण 2: खाली माइग्रेशन बनाएं

python manage.py makemigrations --empty myapp

चरण 3: चरण 2 में बनाई गई माइग्रेशन फ़ाइल में माइग्रेशन क्लास संपादित करें

class Migration(migrations.Migration):

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

operations = [
    migrations.AlterField(
        model_name='AnotherModel',
        name='foo',
        field=models.IntegerField(),
    ),
    migrations.AlterField(
        model_name='YetAnotherModel',
        name='foo',
        field=models.IntegerField(),
    ),
    migrations.RenameModel('Foo', 'Bar'),
    migrations.AlterField(
        model_name='AnotherModel',
        name='foo',
        field=models.ForeignKey(to='myapp.Bar'),
    ),
    migrations.AlterField(
        model_name='YetAnotherModel',
        name='foo',
        field=models.ForeignKey(to='myapp.Bar'),
    ),
    migrations.RenameField('AnotherModel', 'foo', 'bar'),
    migrations.RenameField('YetAnotherModel', 'foo', 'bar')
]

चरण 4: माइग्रेशन लागू करें

python manage.py migrate

किया हुआ

पीएस मैंने Django 1.9 पर इस दृष्टिकोण की कोशिश की है


मैंने संस्करण 10 से संस्करण 11 तक Django को अपग्रेड किया:

sudo pip install -U Django

( -U "अपग्रेड" के लिए) और यह समस्या हल हो गई।


दुर्भाग्यवश, मुझे समस्याओं का नाम बदलने के साथ समस्याएं (प्रत्येक django 1.x) मिली जो डीबी में पुराने tablenames छोड़ते हैं (पुराने टेबल पर कुछ भी कोशिश नहीं करते हैं, बस मॉडल का नाम बदलें)।

उस मामले के लिए समाधान:

class Foo(models.Model):
     name = models.CharField(unique=True, max_length=32)
     ...
Bar = Foo

Django 1.10 के लिए, मैं बस मैकेमिग्रेशंस चलाकर दो मॉडल वर्ग के नाम (एक विदेशी कुंजी सहित, और डेटा के साथ) को बदलने में कामयाब रहा, और फिर ऐप के लिए माइग्रेट कर दिया। Makemigrations कदम के लिए, मुझे पुष्टि करनी थी कि मैं टेबल नाम बदलना चाहता था। माइग्रेट ने बिना किसी समस्या के तालिकाओं के नाम बदल दिए।

तब मैंने विदेशीकी क्षेत्र का नाम मिलान करने के लिए बदल दिया, और फिर से यह पुष्टि करने के लिए माकमेग्रेशन द्वारा पूछा गया कि मैं नाम बदलना चाहता हूं। परिवर्तन करने से माइग्रेट करें।

इसलिए मैंने इसे बिना किसी विशेष फ़ाइल संपादन के दो चरणों में लिया। मुझे पहली बार त्रुटियां मिलीं क्योंकि मैं @ wasibigeek द्वारा उल्लिखित admin.py फ़ाइल को बदलना भूल गया था।


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

तो, समाधान एक समय में एक टेबल का नाम बदलना, models.py में मॉडल वर्ग का नाम बदलना, संभवतः views.py , और माइग्रेशन करना है। इसके बाद अन्य संदर्भों के लिए अपना कोड (मॉडल श्रेणी के नाम, संबंधित (क्वेरी) नाम, परिवर्तनीय नाम) का निरीक्षण करें। यदि आवश्यक हो, तो माइग्रेशन करें। फिर, वैकल्पिक रूप से इन सभी माइग्रेशन को एक में संयोजित करें (आयात को प्रतिलिपि बनाना सुनिश्चित करें)।


मुझे एक ही काम करने की ज़रूरत थी। मैंने मॉडल को एक बार में बदल दिया (यानी, चरण 1 और चरण 5 एक साथ)। फिर एक स्कीमा माइग्रेशन बनाया लेकिन इसे यह संपादित करने के लिए संपादित किया:

class Migration(SchemaMigration):
    def forwards(self, orm):
        db.rename_table('Foo','Bar')

    def backwards(self, orm):
        db.rename_table('Bar','Foo')

यह पूरी तरह से काम किया। मेरे सभी मौजूदा डेटा दिखाए गए, अन्य सभी तालिकाओं को बार ठीक संदर्भित किया गया।

यहां से: https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/


सबसे पहले, मैंने सोचा था कि फिवर की विधि मेरे लिए काम करती है क्योंकि माइग्रेशन चरण 4 तक अच्छी तरह से काम करता है। हालांकि, 'विदेशीकेफिल्ड (फू)' में विदेशी मुद्रा परिवर्तन (फू) 'को किसी भी माइग्रेशन में शामिल नहीं किया गया था। यही कारण है कि जब मैं रिलेशनशिप फ़ील्ड का नाम बदलना चाहता था तो माइग्रेशन विफल रहा (चरण 5-8)। यह इस तथ्य के कारण हो सकता है कि मेरे 'अन्य मॉडेल' और 'YetAnotherModel' को मेरे मामले में अन्य ऐप्स में प्रेषित किया गया है।

इसलिए मैंने नीचे दिए गए चरणों का पालन करके अपने मॉडल और रिलेशनशिप फ़ील्ड का नाम बदलने में कामयाब रहे:

मैंने इस विधि को विशेष रूप से ओट्रानज़र की चाल को अनुकूलित किया।

तो फिवर की तरह मान लें कि हमारे पास myapp में है :

class Foo(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)

और myotherapp में :

class AnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Foo)
    is_ridonkulous = models.BooleanField()

चरण 1:

प्रत्येक OntToOneField (Foo) या ForeignKeyField (Foo) को IntegerField () में बदलें। (यह पूर्ण Foo ऑब्जेक्ट की आईडी को पूर्णांक फ़ील्ड के मान के रूप में रखेगा)।

class AnotherModel(models.Model):
    foo = models.IntegerField()
    is_awesome = models.BooleanField()

class YetAnotherModel(models.Model):
    foo = models.IntegerField()
    is_ridonkulous = models.BooleanField()

फिर

python manage.py makemigrations

python manage.py migrate

चरण 2: (फिवर से चरण 2-4 की तरह)

मॉडल नाम बदलें

class Bar(models.Model):  # <-- changed model name
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)

एक खाली माइग्रेशन बनाएं:

python manage.py makemigrations --empty myapp

फिर इसे संपादित करें:

class Migration(migrations.Migration):

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

    operations = [
        migrations.RenameModel('Foo', 'Bar')
    ]

आखिरकार

python manage.py migrate

चरण 3:

अपने इंटीजरफ़िल्ल्ड () को अपने पिछले विदेशीकेफ़ील्ड, वनटोनफिल्ड में वापस करें लेकिन नए बार मॉडल के साथ बदलें। (पिछला पूर्णांकफील्ड आईडी संग्रहित कर रहा था, इसलिए django समझता है और कनेक्शन को फिर से स्थापित करता है, जो ठंडा है।)

class AnotherModel(models.Model):
    foo = models.ForeignKey(Bar)
    is_awesome = models.BooleanField()

class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Bar)
    is_ridonkulous = models.BooleanField()

फिर करो:

python manage.py makemigrations 

बहुत महत्वपूर्ण बात यह है कि, इस चरण में आपको हर नए माइग्रेशन को संशोधित करना होगा और RenameModel Foo-> बार माइग्रेशन पर निर्भरता जोड़नी होगी। तो अगर दोनों एक और मॉडल और फिर भी एकमात्र मॉडल myotherapp में हैं myotherapp में बनाया माइग्रेशन इस तरह दिखना चाहिए:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '00XX_the_migration_of_myapp_with_renamemodel_foo_bar'),
        ('myotherapp', '00xx_the_migration_of_myotherapp_with_integerfield'),
    ]

    operations = [
        migrations.AlterField(
            model_name='anothermodel',
            name='foo',
            field=models.ForeignKey(to='myapp.Bar'),
        ),
        migrations.AlterField(
            model_name='yetanothermodel',
            name='foo',
            field=models.ForeignKey(to='myapp.Bar')
        ),
    ]

फिर

python manage.py migrate

चरण 4:

आखिरकार आप अपने खेतों का नाम बदल सकते हैं

class AnotherModel(models.Model):
    bar = models.ForeignKey(Bar) <------- Renamed fields
    is_awesome = models.BooleanField()


class YetAnotherModel(models.Model):
    bar = models.ForeignKey(Bar) <------- Renamed fields
    is_ridonkulous = models.BooleanField()

और फिर स्वचालित नामकरण करें

python manage.py makemigrations

(django आपको पूछना चाहिए कि क्या आपने वास्तव में मॉडल नाम का नाम बदल दिया है, हाँ कहें)

python manage.py migrate

और बस!

यह Django1.8 पर काम करता है


अधिकांश यूनिक्स (जिसमें ओएसएक्स शामिल है) में फ़ाइल /usr/share/dict/words





python django django-migrations