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

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. 더 쉬운 방법은?


답변

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

./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'.

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


답변

변경 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)


답변

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

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


답변

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

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


답변