문제

이름을 바꾸려는 모델과 외래 키 관계가 있는 다른 모델이 많이 있는 기존 Django 프로젝트에서 여러 모델의 이름을 바꿀 계획입니다.여러 번의 마이그레이션이 필요할 것이라고 확신하지만 정확한 절차는 잘 모르겠습니다.

다음과 같은 Django 앱 내에서 다음 모델로 시작한다고 가정해 보겠습니다. myapp:

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()

참고하세요 AnotherModel 필드 이름 foo 변경되지 않지만 관계는 다음으로 업데이트됩니다. Bar 모델.내 추론은 한 번에 너무 많이 변경해서는 안 되며 이 필드 이름을 다음으로 변경하면 된다는 것입니다. bar 해당 열의 데이터가 손실될 위험이 있습니다.

2 단계

빈 마이그레이션을 만듭니다.

python manage.py makemigrations --empty myapp

3단계

편집하다 Migration 2단계에서 생성된 마이그레이션 파일의 클래스에 RenameModel 작업 목록에 대한 작업:

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단계

편집하다 Migration 6단계에서 생성된 마이그레이션 파일의 클래스에 RenameField 작업 목록과 관련된 필드 이름에 대한 작업:

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

새 변수 이름을 반영하기 위해 나머지 코드(뷰, 양식 등)를 업데이트하는 것 외에도 이것이 기본적으로 새 마이그레이션 기능이 작동하는 방식입니까?

또한 이것은 많은 단계처럼 보입니다.마이그레이션 작업을 어떤 방식으로든 압축할 수 있나요?

감사해요!

도움이 되었습니까?

해결책

그래서 이것을 시도했을 때 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 및 이전 마이그레이션 파일(!).

업데이트:처럼 세자로 언급했듯이 최신 버전의 Django는 일반적으로 모델의 이름이 변경되었는지 감지하고 질문할 수 있습니다.그러니 시도해 보세요 manage.py makemigrations 먼저 마이그레이션 파일을 확인하세요.

다른 팁

처음에는 4단계까지 마이그레이션이 잘 되었기 때문에 Fiver의 방법이 나에게 맞는다고 생각했다.그러나 'ForeignKeyField(Foo)'에서 'ForeignKeyField(Bar)'로의 암시적 변경은 마이그레이션과 관련이 없습니다.이것이 관계 필드의 이름을 바꾸려고 할 때 마이그레이션이 실패한 이유입니다(5-8단계).이는 내 경우 'AnotherModel' 및 'YetAnotherModel'이 다른 앱에서 전달된다는 사실 때문일 수 있습니다.

그래서 아래 단계를 수행하여 모델과 관계 필드의 이름을 바꿨습니다.

나는 다음의 방법을 적용했습니다. 이것 특히 otranszer의 트릭.

Fiver처럼 우리가 마이앱:

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 단계:

모든 OneToOneField(Foo) 또는 ForeignKeyField(Foo)를 IntegerField()로 변환합니다.(이것은 관련 Foo 객체의 ID를 정수 필드의 값으로 유지합니다).

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 단계:(Fiver의 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단계:

IntegerField()를 이전 ForeignKeyField 또는 OneToOneField로 되돌리되 새로운 Bar 모델을 사용하여 변환하세요.(이전 정수 필드는 ID를 저장하고 있었기 때문에 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-> Bar 마이그레이션에 대한 종속성을 추가해야 한다는 것입니다.따라서 AnotherModel과 YetAnotherModel이 모두 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에서 작동합니다.

나도 같은 일을 해야 했어요.모델을 한꺼번에 변경했습니다(즉, 1단계와 5단계를 함께 변경했습니다).그런 다음 스키마 마이그레이션을 생성했지만 다음과 같이 편집했습니다.

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

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

이것은 완벽하게 작동했습니다.기존 데이터가 모두 표시되었고 다른 모든 테이블에서는 Bar를 참조했습니다.

여기에서: https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/

Django 1.10의 경우 Makemigrations를 실행한 다음 앱에 대해 Migrate를 실행하여 두 개의 모델 클래스 이름(ForeignKey 포함 및 데이터 포함)을 변경했습니다.Makemigrations 단계에서는 테이블 이름을 변경할 것인지 확인해야 했습니다.마이그레이션은 문제 없이 테이블 이름을 변경했습니다.

그런 다음 일치하도록 ForeignKey 필드의 이름을 변경했고 Makemigrations에서 다시 이름을 변경할 것인지 확인하라는 요청을 받았습니다.변경한 것보다 마이그레이션하십시오.

그래서 특별한 파일 편집 없이 2단계로 진행했습니다.@wasibigeek이 언급한 대로 admin.py 파일을 변경하는 것을 잊어버렸기 때문에 처음에는 오류가 발생했습니다.

나는 또한 v.thorey가 설명한 대로 문제에 직면했고 그의 접근 방식이 매우 유용하지만 Fiver가 1~4단계 없이 설명한 것처럼 실제로는 5~8단계인 더 적은 단계로 압축될 수 있음을 발견했습니다. 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단계에서 생성된 마이그레이션 파일에서 Migration 클래스를 편집합니다.

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에서 이 접근 방식을 시도했습니다.

Django 버전 1.9.4를 사용하고 있습니다.

나는 다음 단계를 따랐습니다:-

나는 단지 모델 oldname의 이름을 newName run로 바꿨습니다. python manage.py makemigrations.그것은 당신에게 요청할 것입니다Did you rename the appname.oldName model to NewName? [y/N] Y를 선택하세요

달리다 python manage.py migrate 그리고 그것은 당신에게 물어볼 것입니다

다음 콘텐츠 유형은 오래되었으므로 삭제해야 합니다.

appname | oldName
appname | NewName

외국 키로 이러한 콘텐츠 유형과 관련된 모든 객체도 삭제됩니다.정말로 이 콘텐츠 유형을 삭제하시겠습니까?확실하지 않다면 '아니요'라고 대답하세요.

Type 'yes' to continue, or 'no' to cancel: Select No

모든 기존 데이터의 이름을 바꾸고 이름이 지정된 새 테이블로 마이그레이션합니다.

불행하게도 데이터베이스에 오래된 테이블 이름을 남기는 이름 바꾸기 마이그레이션에서 문제(각 django 1.x)를 발견했습니다.

Django는 이전 테이블에서 아무것도 시도하지 않고 자신의 모델 이름을 변경합니다.일반적으로 외래 키 및 인덱스와 관련된 동일한 문제 - 변경 사항이 Django에서 제대로 추적되지 않습니다.

가장 간단한 해결책(해결 방법):

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

실제 솔루션 (모든 지수, 제약, 트리거, 이름 등을 2 개의 커밋으로 전환하는 쉬운 방법이 아니라 오히려 더 작은 테이블):

커밋 A:

  1. 생성하다 같은 오래된 모델로
# deprecated - TODO: TO BE REMOVED
class Foo(model.Model):
    ...

class Bar(model.Model):
    ...
  1. 새 모델과 작동하도록 코드 전환 Bar 오직.(스키마의 모든 관계 포함)

마이그레이션 준비 중 RunPython, FOO에서 막대로 데이터를 복사하는 (포함 id 푸의)

  1. 선택적 최적화(더 큰 테이블에 필요한 경우)

커밋 B: (서두르지 마세요. 팀 전체가 마이그레이션될 때 수행하세요)

  1. 구형 모델의 안전한 낙하 Foo

추가 정리:

  • 마이그레이션 스쿼시

Django의 버그:

몇 개의 테이블 이름을 바꿔야 했습니다.그러나 Django에서는 단 하나의 모델 이름 변경만 발견했습니다.이는 Django가 모델을 추가하고 제거하는 과정을 반복하기 때문에 발생했습니다.각 쌍에 대해 동일한 앱에 속해 있는지 확인하고 동일한 필드.단 하나의 테이블에만 이름을 바꿀 테이블에 대한 외래 키가 없습니다(외래 키에는 모델 클래스 이름이 포함되어 있음).즉, 단 하나의 테이블에만 필드 변경 사항이 없습니다.그렇기 때문에 주목을 받았습니다.

따라서 해결책은 한 번에 하나의 테이블 이름을 바꾸고 모델 클래스 이름을 변경하는 것입니다. models.py, 아마도 views.py, 마이그레이션을 수행합니다.그런 다음 코드에서 다른 참조(모델 클래스 이름, 관련(쿼리) 이름, 변수 이름)를 검사합니다.필요한 경우 마이그레이션을 수행합니다.그런 다음 선택적으로 이러한 모든 마이그레이션을 하나로 결합합니다(가져오기도 복사해야 함).

나는 @ceasaro 단어를 만들 것입니다. 이것에 대한 그의 의견은 내 것입니다. 답변.

최신 버전의 Django는 변경 사항을 감지하고 수행된 작업에 대해 물어볼 수 있습니다.또한 Django가 일부 마이그레이션 명령의 실행 순서를 혼합할 수도 있다는 점을 덧붙이고 싶습니다.

작은 변화를 적용하고 실행하는 것이 현명할 것입니다. makemigrations 그리고 migrate 오류가 발생하면 마이그레이션 파일을 편집할 수 있습니다.

오류를 방지하기 위해 일부 라인의 실행 순서를 변경할 수 있습니다.

ceasaro 의견을 확인하고 추가하고 싶었습니다.Django 2.0에서는 이제 이 작업을 자동으로 수행하는 것 같습니다.

저는 Jango 2.2.1을 사용하고 있습니다. 모델 이름을 바꾸고 makemigration을 실행하기만 하면 됩니다.

여기에서는 특정 클래스의 이름을 A에서 B로 바꿨는지 묻는 메시지가 나타납니다. 예를 선택하고 마이그레이션을 실행했는데 모두 작동하는 것 같습니다.

참고 프로젝트/마이그레이션 폴더 내의 모든 파일에서 이전 모델 이름의 이름을 바꾸지 않았습니다.

PyCharm과 같은 좋은 IDE를 사용하는 경우 모델 이름을 마우스 오른쪽 버튼으로 클릭하고 리팩터링 -> 이름 바꾸기를 수행할 수 있습니다.이렇게 하면 모델을 참조하는 모든 코드를 검토하는 수고를 덜 수 있습니다.그런 다음 makemigration을 실행하고 마이그레이션합니다.Django 2+는 단순히 이름 변경을 확인합니다.

Django를 버전 10에서 버전 11로 업그레이드했습니다.

sudo pip install -U Django

(-U "업그레이드"의 경우) 문제가 해결되었습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top