मैं एक 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
फिर से चलाने के लिए करना है।