하나의 장고 앱에서 새 모델로 모델을 어떻게 관리합니까?
네 가지 모델의 장고 앱이 있습니다. 이제이 모델 중 하나가 별도의 앱에 나오는 것을 알고 있습니다. 설치를 위해 설치를 자동으로 처리 할 수 있습니다. 이전 앱에서 모델 중 하나를 새 모델로 비용을 부담해야합니까?
또한 다수의 반복 가능한 프로세스가 점에 유의하십시오.
남쪽을 사용하여 마이그레이션하는 방법
공통 및 특정의 두 가지 앱이 어디 가정 해 보겠습니다.
myproject/
|-- common
| |-- migrations
| | |-- 0001_initial.py
| | `-- 0002_create_cat.py
| `-- models.py
`-- specific
|-- migrations
| |-- 0001_initial.py
| `-- 0002_create_dog.py
`-- models.py
이제 common.models.cat 모델을 특정 앱 (정확히 specific.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
사물을 마이그레이션합니다.
스키마 업그레이드에는 공통 앱을 사용하고 다운 그레이드에는 특정 앱을 사용했습니다. 작동 원리 때문입니다.
Potr Czachur 의 답변 을 바탕으로 ForeignKeys가 관련된 상황은 더 복잡하고 약간 다르게 처리해야합니다.
(다음 예제 는 현재 답변에서 참조 된 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')
보다시피, FK는 새로운 테이블을 참조해야합니다. 하기 전에 추가해야하지만 롤백이 작동하기 때문에 롤백이 작동하는지 확인해야 합니다. 의존성은 반대 방향으로 적용 됩니다.
# 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
앞으로 마이그레이션 할 때 만에 뒤쪽을 마이그레이션 할 때 반대 순서를 . 가 떠나기 경우 우리 db.rename_table('specific_cat', 'common_cat')
에서 specific
롤백의 common
표 참조 된 테이블이 존재하지 않는 것이기 때문에 외래 키를 마이그레이션 할 때 롤백이 실패합니다.
이 방법이 기존 솔루션보다 "실제"상황에 더 가깝기를 바랍니다. 누군가 도움이 될 것입니다. 건배!
모델은 앱과 번호가 연결되어있어 이동이 매우 간단합니다. Django는 데이터베이스 테이블 이름에 앱 이름을 사용하는 앱을 이동하려는 SQL ALTER TABLE
문을 통해 데이터베이스 테이블의 이름을 바꾸거나 더 간단하게 모델 클래스 의 db_table
매개 변수 를 사용 Meta
하여하여 고명.
코드에서 지금까지 ContentTypes 또는 일반 관계를 또는 또는 사용한 경우 app_label
기존 관계가 유지되도록 이동중인 모델을 가리키는 컨텐트 유형의 이름을 바꾸고 싶을을 구석으로입니다 .
물론 보존 할 데이터가없는 경우 가장 쉬운 방법은 데이터베이스 테이블을 완전히 삭제하고 ./manage.py syncdb
다시 실행 하는 것입니다.
Potr의 수정 사항에 대한 또 하나의 수정 사항이 있습니다. specific / 0003_create_cat에 다음을 추가하십시오.
depends_on = (
('common', '0002_create_cat'),
)
이 설정이 설정되어 있지 않은 South는 특정 / 0003_create_cat 이 실행될 common_cat
때 테이블이 존재하는 보증하지 오류가 발생합니다.django.db.utils.OperationalError: no such table: common_cat
언어가 명시 적으로 설정되어 있지 않은 경우 South는 사전 순서대로 마이그레이션 을 실행합니다 . 그래서 common
앞에 오는 specific
모든 common
아마 Potr이 원래의 예에서 재현 할 것, 그래서의 이전, 테이블 이름을 사전에 것입니다. 하지만 이름 변경을 만약 common
에 app2
와 specific
에 app1
이 문제로 실행됩니다.
내가 여기에 몇 번 돌아와서 공식화하기로 결정한 이후로 현재 어떤 프로세스.
이것은 원래 Potr Czachur의 대답 과 Matt Briançon의 대답에 따라 남쪽 0.8.4를 사용하여 작성합니다.
1 단계. 하위 외래 키 관계 발견
# Caution: This finds OneToOneField and ForeignKey.
# I don't know if this finds all the ways of specifying ManyToManyField.
# Hopefully Django or South throw errors if you have a situation like that.
>>> Cat._meta.get_all_related_objects()
[<RelatedObject: common:toy related to cat>,
<RelatedObject: identity:microchip related to cat>]
이 확장 사례에서 우리는 다음과 같은 다른 관련 모델을 발견했습니다.
# Inside the "identity" app...
class Microchip(models.Model):
# In reality we'd probably want a ForeignKey, but to show the OneToOneField
identifies = models.OneToOneField(Cat)
...
2 단계. 더 생성
# Create the "new"-ly renamed model
# Yes I'm changing the model name in my refactoring too.
python manage.py schemamigration specific create_kittycat --auto
# Drop the old model
python manage.py schemamigration common drop_cat --auto
# Update downstream apps, so South thinks their ForeignKey(s) are correct.
# Can skip models like Toy if the app is already covered
python manage.py schemamigration identity update_microchip_fk --auto
3 단계. 소스 제어 : 지금까지 변경 사항을 커밋합니다.
업데이트 된 앱에서 마이그레이션을 작성하는 팀 동료와 같은 병합 충돌이 발생하면 프로세스를 더 반복 가능한 프로세스로 만듭니다.
단계 4. 추가간에 추가를 추가하십시오.
기본적으로 create_kittycat
모든 것의 현재 상태에 의존하고 모든 것에 의존합니다 create_kittycat
.
# create_kittycat
class Migration(SchemaMigration):
depends_on = (
# Original model location
('common', 'the_one_before_drop_cat'),
# Foreign keys to models not in original location
('identity', 'the_one_before_update_microchip_fk'),
)
...
# drop_cat
class Migration(SchemaMigration):
depends_on = (
('specific', 'create_kittycat'),
)
...
# update_microchip_fk
class Migration(SchemaMigration):
depends_on = (
('specific', 'create_kittycat'),
)
...
5 단계. 테이블 이름을 바꾸고 자합니다.
# create_kittycat
class Migration(SchemaMigration):
...
# Hopefully for create_kittycat you only need to change the following
# 4 strings to go forward cleanly... backwards will need a bit more work.
old_app = 'common'
old_model = 'cat'
new_app = 'specific'
new_model = 'kittycat'
# You may also wish to update the ContentType.name,
# personally, I don't know what its for and
# haven't seen any side effects from skipping it.
def forwards(self, orm):
db.rename_table(
'%s_%s' % (self.old_app, self.old_model),
'%s_%s' % (self.new_app, self.new_model),
)
if not db.dry_run:
# For permissions, GenericForeignKeys, etc to work properly after migrating.
orm['contenttypes.contenttype'].objects.filter(
app_label=self.old_app,
model=self.old_model,
).update(
app_label=self.new_app,
model=self.new_model,
)
# Going forwards, should be no problem just updating child foreign keys
# with the --auto in the other new South migrations
def backwards(self, orm):
db.rename_table(
'%s_%s' % (self.new_app, self.new_model),
'%s_%s' % (self.old_app, self.old_model),
)
if not db.dry_run:
# For permissions, GenericForeignKeys, etc to work properly after migrating.
orm['contenttypes.contenttype'].objects.filter(
app_label=self.new_app,
model=self.new_model,
).update(
app_label=self.old_app,
model=self.old_model,
)
# Going backwards, you probably should copy the ForeignKey
# db.alter_column() changes from the other new migrations in here
# so they run in the correct order.
#
# Test it! See Step 6 for more details if you need to go backwards.
db.alter_column('common_toy', 'belongs_to_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['common.Cat']))
db.alter_column('identity_microchip', 'identifies_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['common.Cat']))
# drop_cat
class Migration(SchemaMigration):
...
def forwards(self, orm):
# Remove the db.delete_table(), if you don't at Step 7 you'll likely get
# "django.db.utils.ProgrammingError: table "common_cat" does not exist"
# Leave existing db.alter_column() statements here
db.alter_column('common_toy', 'belongs_to_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['specific.KittyCat']))
def backwards(self, orm):
# Copy/paste the auto-generated db.alter_column()
# into the create_kittycat migration if you need backwards to work.
pass
# update_microchip_fk
class Migration(SchemaMigration):
...
def forwards(self, orm):
# Leave existing db.alter_column() statements here
db.alter_column('identity_microchip', 'identifies_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['specific.KittyCat']))
def backwards(self, orm):
# Copy/paste the auto-generated db.alter_column()
# into the create_kittycat migration if you need backwards to work.
pass
단계 6. 작업을 위해 거꾸로 ()가 필요하고 KeyError가 거꾸로 실행되는 경우에만.
# the_one_before_create_kittycat
class Migration(SchemaMigration):
# You many also need to add more models to South's FakeORM if you run into
# more KeyErrors, the trade-off chosen was to make going forward as easy as
# possible, as that's what you'll probably want to do once in QA and once in
# production, rather than running the following many times:
#
# python manage.py migrate specific <the_one_before_create_kittycat>
models = {
...
# Copied from 'identity' app, 'update_microchip_fk' migration
u'identity.microchip': {
'Meta': {'object_name': 'Microchip'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'identifies': ('django.db.models.fields.related.OneToOneField', [], {to=orm['specific.KittyCat']})
},
...
}
7 단계. 테스트. 저에게 효과가있는 것이 실제 상황에 충분하지 않을 수 있습니다. :)
python manage.py migrate
# If you need backwards to work
python manage.py migrate specific <the_one_before_create_kittycat>
따라서 위의 @Potr의 원래 응답을 사용하면 South 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';")
Daniel Roseman이 그의 답변에서 제안한 것 중 하나에 대해 좀 더 명확한 버전을 제공하겠습니다.
db_table
기존 테이블 이름을 가리 키도록 이동 한 모델 의 메타 속성 만 변경하면 (DJango가 새 이름을 지정하는 대신에 삭제하고했을 경우 syncdb
) 복잡한 South 마이그레이션을 피할 수 있습니다. 예 :
실물 :
# app1/models.py
class MyModel(models.Model):
...
이사 후 :
# app2/models.py
class MyModel(models.Model):
class Meta:
db_table = "app1_mymodel"
이제 당신은 단지를 업데이트 할 수있는 데이터 마이그레이션 할 필요 app_label
에 대한 MyModel
에서 django_content_type
테이블을 당신은 좋은 갈 수있을 것입니다 ...
실행 ./manage.py datamigration django update_content_type
한 다음 South가 생성 한 파일을 편집합니다.
def forwards(self, orm):
moved = orm.ContentType.objects.get(app_label='app1', model='mymodel')
moved.app_label = 'app2'
moved.save()
def backwards(self, orm):
moved = orm.ContentType.objects.get(app_label='app2', model='mymodel')
moved.app_label = 'app1'
moved.save()
'IT' 카테고리의 다른 글
Symfony2에서 현재 사용자를 얼마나 많이 얻었습니까? (0) | 2020.07.09 |
---|---|
멀티 컨트롤러-파이프와 큐 (0) | 2020.07.09 |
Xcode에서 빌드 구성 추가 (0) | 2020.07.09 |
반응에서 외장 환경 변수를 사용 설정? (0) | 2020.07.09 |
여러 테이블에 MySQL 삽입? (0) | 2020.07.09 |