Django / South를 사용하여 모델 이름을 바꾸는 가장 쉬운 방법은 무엇입니까?


141

South의 사이트, Google 및 SO에서 이에 대한 답변을 찾고 있었지만 간단한 방법을 찾지 못했습니다.

South를 사용하여 Django 모델의 이름을 바꾸고 싶습니다. 다음이 있다고 가정하십시오.

class Foo(models.Model):
    name = models.CharField()

class FooTwo(models.Model):
    name = models.CharField()
    foo = models.ForeignKey(Foo)

Foo를 Bar로 변환하고 싶습니다.

class Bar(models.Model):
    name = models.CharField()

class FooTwo(models.Model):
    name = models.CharField()
    foo = models.ForeignKey(Bar)

간단하게 유지하려면 이름을에서 (으) Foo로 변경하려고 Bar하지만 지금 은 foo멤버를 무시하십시오 FooTwo.

South를 사용하여 가장 쉬운 방법은 무엇입니까?

  1. 아마도 데이터 마이그레이션을 할 수는 있지만 꽤 관련이있는 것 같습니다.
  2. 예를 들어 db.rename_table('city_citystate', 'geo_citystate'), 사용자 지정 마이그레이션을 작성 하지만이 경우 외래 키를 수정하는 방법을 잘 모르겠습니다.
  3. 더 쉬운 방법은?

5
참조 stackoverflow.com/questions/3235995/... 이름 만 바꾼위한 모델 필드를 보다는 모델 .
기계 달팽이

Django를위한 최적화 된 솔루션> = 1.8 stackoverflow.com/questions/25091130/…
화학 프로그래머

답변:


130

첫 번째 질문에 대답하기 위해 간단한 모델 / 테이블 이름 바꾸기는 매우 간단합니다. 다음 명령을 실행하십시오 :

./manage.py schemamigration yourapp rename_foo_to_bar --empty

(업데이트 2 : 시도 --auto대신에 --empty아래의 경고를 피하기 위해 팁을위한 @KFB 덕분에..)

남쪽의 이전 버전을 사용하는 경우 startmigration대신에 필요 합니다 schemamigration.

그런 다음 마이그레이션 파일을 다음과 같이 수동으로 편집하십시오.

class Migration(SchemaMigration):

    def forwards(self, orm):
        db.rename_table('yourapp_foo', 'yourapp_bar')


    def backwards(self, orm):
        db.rename_table('yourapp_bar','yourapp_foo')   

db_table모델 클래스에서 Meta 옵션을 사용하여이 작업을 더 간단하게 수행 할 수 있습니다 . 그러나 그렇게 할 때마다 코드베이스의 레거시 가중치가 증가합니다. 클래스 이름이 테이블 이름과 다르면 코드를 이해하고 유지하기가 더 어려워집니다. 명확성을 위해 이와 같은 간단한 리팩토링을 완전히 지원합니다.

(업데이트) 방금 프로덕션에서 이것을 시도했지만 마이그레이션을 적용하려고 할 때 이상한 경고가 표시되었습니다. 그것은 말했다 :

The following content types are stale and need to be deleted:

    yourapp | foo

Any objects related to these content types by a foreign key will also
be deleted. Are you sure you want to delete these content types?
If you're unsure, answer 'no'.

나는 "아니오"라고 대답했고 모든 것이 괜찮은 것 같습니다.


3
--empty 대신 --auto를 사용하여 스키마 마이그레이션을 생성하여 Leopd에서 오류 메시지를 피할 수있었습니다. 그런 다음 마이그레이션 파일을 편집하여 테이블의 삭제 / 작성을 db.rename_table () 호출로 변경했습니다. 이것은 매우 잘 작동 한 것 같습니다.
KFB

4
이 기술을 2011 년 9 월 2 일에 오류없이 사용했습니다. 최신 버전의 South가 오류로 문제를 해결했을 수도 있습니다.
Chip Tol

1
이 업데이트를 유지해 주셔서 감사합니다! 아래 Jian의 답변에 따르면 "send_create_signal"호출을 유지하는 것이 중요합니다. 이에 대해 알고 있습니까? 동의하면 예제 마이그레이션을 업데이트하는 것이 좋습니다.
mrooney

5
이 경우 해당 테이블의 인덱스 이름이 바뀌지 않습니다. 나중에 이전 테이블과 동일한 이름으로 새 테이블을 만들면 인덱스 이름 충돌로 인해 오류가 발생할 수 있습니다. 이 기술을 사용하고 있었지만 이제부터 명시 적으로 새 테이블을 만들고 데이터를 마이그레이션 한 다음 이전 테이블을 삭제하려고합니다.
Jeremy Banks

3
M2M 테이블과 같은 자동 생성 테이블의 열 이름도이 방법으로 마이그레이션되지 않습니다.
spookylukey

66

변경 models.py후 실행

./manage.py schemamigration --auto myapp

마이그레이션 파일을 검사하면 테이블이 삭제되고 새 테이블이 생성됩니다.

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Deleting model 'Foo'                                                                                                                      
        db.delete_table('myapp_foo')

        # Adding model 'Bar'                                                                                                                        
        db.create_table('myapp_bar', (
        ...
        ))
        db.send_create_signal('myapp', ['Bar'])

    def backwards(self, orm):
        ...

이것은 당신이 원하는 것이 아닙니다. 대신 다음과 같이 마이그레이션을 편집하십시오.

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Renaming model from 'Foo' to 'Bar'                                                                                                                      
        db.rename_table('myapp_foo', 'myapp_bar')                                                                                                                        
        if not db.dry_run:
            orm['contenttypes.contenttype'].objects.filter(
                app_label='myapp', model='foo').update(model='bar')

    def backwards(self, orm):
        # Renaming model from 'Bar' to 'Foo'                                                                                                                      
        db.rename_table('myapp_bar', 'myapp_foo')                                                                                                                        
        if not db.dry_run:
            orm['contenttypes.contenttype'].objects.filter(app_label='myapp', model='bar').update(model='foo')

update명령문 이 없으면 db.send_create_signal호출은 ContentType새 모델 이름으로 새로 작성합니다 . 그러나 그것은 단지 더 나은의 update(가) ContentType경우 (A를 통해, 예를 들어, 데이터베이스가 가리키는 객체가 이미 있습니다 GenericForeignKey).

또한 이름이 바뀐 모델의 외래 키인 일부 열의 이름을 바꾼 경우 잊지 마십시오.

db.rename_column(myapp_model, foo_id, bar_id)

2
KeyError : "이 마이그레이션에서는 'contenttypes'앱의 'contenttype'모델을 사용할 수 없습니다."라는 오류가 발생합니다. 또한 django_content_type 테이블이 있지만 contenttypes 테이블은 없습니다. (Django 1.6)
Seth

2
@Seth 별도의 데이터 마이그레이션에서 ContentType 모델을 업데이트 contenttypes.ContentType하고에 --frozen플래그를 사용하여 고정 된 모델에 모델을 추가하여이 문제를 해결했습니다 ./manage.py datamigration. 예를 들면 다음과 같습니다 ./manage.py datamigration --frozen contenttypes myapp update_contenttypes.. 그런 다음 위에 지정된 컨텐츠 유형 업데이트 코드를 사용하여 myapp_migrations / NNNN_update_contenttypes.py를 편집하십시오.
Geoffrey Hing

@GeoffreyHing 매개 변수가 고정되지 않은 것 같습니다. south.readthedocs.io/en/latest/ormfreezing.html 그러나 당신의 도움을 주셔서 대단히 감사합니다, 그것은 정말로 도움이되었습니다.
ccsakuweb

5

남쪽은 그것을 할 수 없습니다-그것이 무엇을 Bar나타내는지를 어떻게 알 Foo수 있습니까? 이것은 내가 맞춤 마이그레이션을 작성하는 일종의 것입니다. 당신은 변경할 수 있습니다ForeignKey위에서 한 것처럼 코드를 필드와 테이블의 이름을 바꾸는 경우입니다.

마지막으로 정말로해야합니까? 아직 verbose_name메타 이름을 사용할 수있는 경우 모델 이름을 아직 변경하지 않아도됩니다. 모델 이름은 구현 세부 사항 일뿐 입니다.


7
또는 코드에서 모델 이름을 바꾸지 만 db_table메타 옵션을 사용 하여 데이터베이스 테이블 이름을 동일하게 유지하십시오.
Daniel Roseman

@Daniel- db_table외래 키 이름을 파생시키는 데 사용 되는지 알고 있습니까?
도미닉 로저

나는 그것을 믿는다. 모델 이름을 변경하고 db_table을 설정하면 모든 것이 여전히 예상대로 작동합니다.
Davor Lucic

1
@DanielRoseman 이것은 전체 스레드에서 최고의 솔루션입니다!
조릭

-1

위의 Leopd 솔루션을 따랐습니다. 그러나 모델 이름은 변경되지 않았습니다. 코드에서 수동으로 변경했습니다 (FK라고하는 관련 모델에서도). 그리고 남쪽으로 이주했지만 --fake 옵션을 사용했습니다. 모델 이름과 테이블 이름이 동일합니다.

방금 모델 이름 변경부터 시작한 다음 마이그레이션 파일을 적용하기 전에 편집 할 수 있습니다. 훨씬 더 깨끗합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.