用于重命名模型和关系字段的Django迁移策略

问题:用于重命名模型和关系字段的Django迁移策略

我打算重命名现有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

第三步

编辑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

除了更新其余代码(视图,表单等)以反映新的变量名之外,这基本上是新的迁移功能如何起作用的吗?

另外,这似乎需要很多步骤。迁移操作可以某种方式压缩吗?

谢谢!

I’m planning to rename several models in an existing Django project where there are many other models that have foreign key relationships to the models I would like to rename. I’m fairly certain this will require multiple migrations, but I’m not sure of the exact procedure.

Let’s say I start out with the following models within a Django app called 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()

I want to rename the Foo model because the name doesn’t really make sense and is causing confusion in the code, and Bar would make for a much clearer name.

From what I have read in the Django development documentation, I’m assuming the following migration strategy:

Step 1

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

Note the AnotherModel field name for foo doesn’t change, but the relation is updated to the Bar model. My reasoning is that I shouldn’t change too much at once and that if I changed this field name to bar I would risk losing the data in that column.

Step 2

Create an empty migration:

python manage.py makemigrations --empty myapp

Step 3

Edit the Migration class in the migration file created in step 2 to add the RenameModel operation to the operations list:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar')
    ]

Step 4

Apply the migration:

python manage.py migrate

Step 5

Edit the related field names in 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()

Step 6

Create another empty migration:

python manage.py makemigrations --empty myapp

Step 7

Edit the Migration class in the migration file created in step 6 to add the RenameField operation(s) for any related field names to the operations list:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0002_rename_fields'),  # <-- is this okay?
    ]

    operations = [
        migrations.RenameField('AnotherModel', 'foo', 'bar'),
        migrations.RenameField('YetAnotherModel', 'foo', 'bar')
    ]

Step 8

Apply the 2nd migration:

python manage.py migrate

Aside from updating the rest of the code (views, forms, etc.) to reflect the new variable names, is this basically how the new migration functionality would work?

Also, this seems like a lot of steps. Can the migration operations be condensed in some way?

Thanks!


回答 0

因此,当我尝试此操作时,您似乎可以将步骤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甚至更旧的迁移文件(!),则可能会遇到一些错误。

更新:正如ceasaro所提到的,较新版本的Django通常能够检测并询问是否重命名了模型。因此,请先尝试manage.py makemigrations,然后检查迁移文件。

So when I tried this, it seems you can condense Step 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')
    ]

You may get some errors if you don’t update the names where it’s imported e.g. admin.py and even older migration files (!).

Update: As ceasaro mentions, newer versions of Django are usually able to detect and ask if a model is renamed. So try manage.py makemigrations first and then check the migration file.


回答 1

最初,我认为Fiver的方法很适合我,因为迁移在第4步之前都可以正常进行。但是,在任何迁移中,从“ ForeignKeyField(Foo)”到“ ForeignKeyField(Bar)”的隐式更改均不相关。这就是为什么当我想重命名关系字段时迁移失败(步骤5-8)。这可能是由于我的案例中我的“ AnotherModel”和“ YetAnotherModel”是在其他应用中分派的。

因此,我设法按照以下步骤重命名我的模型和关系字段:

我改编自方法和otranzer的特别的特技。

因此,就像Fiver一样,我们在myapp中拥有

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保留为integerfield的值)。

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

第三步:

将您的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

At first, I thought that Fiver’s method worked for me because the migration worked well until step 4. However, the implicit changes ‘ForeignKeyField(Foo)’ into ‘ForeignKeyField(Bar)’ was not related in any migrations. This is why migration failed when I wanted to rename relationship fields (step 5-8). This might be due to the fact that my ‘AnotherModel’ and ‘YetAnotherModel’ are dispatched in other apps in my case.

So I managed to rename my models and relationship fields doing following below steps:

I adapted the method from this and particularly the trick of otranzer.

So like Fiver let’s say we have in myapp:

class Foo(models.Model):
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)

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

Step 1:

Transform every OneToOneField(Foo) or ForeignKeyField(Foo) into IntegerField(). (This will keep the id of related Foo object as value of the integerfield).

class AnotherModel(models.Model):
    foo = models.IntegerField()
    is_awesome = models.BooleanField()

class YetAnotherModel(models.Model):
    foo = models.IntegerField()
    is_ridonkulous = models.BooleanField()

Then

python manage.py makemigrations

python manage.py migrate

Step 2: (Like step 2-4 from Fiver)

Change the model name

class Bar(models.Model):  # <-- changed model name
    name = models.CharField(unique=True, max_length=32)
    description = models.TextField(null=True, blank=True)

Create an empty migration:

python manage.py makemigrations --empty myapp

Then edit it like:

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.RenameModel('Foo', 'Bar')
    ]

Eventually

python manage.py migrate

Step 3:

Transform Back your IntegerField() into their previous ForeignKeyField or OneToOneField but with the new Bar Model. (The previous integerfield was storing the id, so django understand that and reestablish the connection, which is cool.)

class AnotherModel(models.Model):
    foo = models.ForeignKey(Bar)
    is_awesome = models.BooleanField()

class YetAnotherModel(models.Model):
    foo = models.ForeignKey(Bar)
    is_ridonkulous = models.BooleanField()

Then do:

python manage.py makemigrations 

Very importantly, at this step you have to modify every new migrations and add the dependency on the RenameModel Foo-> Bar migrations. So if both AnotherModel and YetAnotherModel are in myotherapp the created migration in myotherapp must look like this:

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')
        ),
    ]

Then

python manage.py migrate

Step 4:

Eventually you can rename your fields

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

and then do automatic renaming

python manage.py makemigrations

(django should ask you if you actually renamed the modelname, say yes)

python manage.py migrate

And that’s it!

This works on Django1.8


回答 2

我需要做同样的事情并遵循。我一次更改了模型(Fiver回答中的步骤1和5)。然后创建模式迁移,但将其编辑为:

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

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

这工作得很好。我所有的现有数据都显示出来,其他所有表都引用了Bar fine。

从这里开始:https : //hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/

I needed to do the same thing and follow. I changed the model all at once (Steps 1 and 5 together from Fiver’s answer). Then created a schema migration but edited it to be this:

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

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

This worked perfectly. All my existing data showed up, all the other tables referenced Bar fine.

from here: https://hanmir.wordpress.com/2012/08/30/rename-model-django-south-migration/


回答 3

对于Django 1.10,我仅通过运行Makemigrations,然后为该应用程序迁移,就设法更改了两个模型类名称(包括ForeignKey和数据)。对于Makemigrations步骤,我必须确认我想更改表名称。迁移更改表的名称没有问题。

然后,我更改了ForeignKey字段的名称以使其匹配,然后Makemigrations再次要求我确认要更改名称。迁移比进行更改。

因此,我分两步进行了此操作,而无需进行任何特殊的文件编辑。起初我确实得到了错误,因为我忘记更改admin.py文件,如@wasibigeek所述。

For Django 1.10, I managed to change two model class names (including a ForeignKey, and with data) by simply running Makemigrations, and then Migrate for the app. For the Makemigrations step, I had to confirm that I wanted to change the table names. Migrate changed the names of the tables without a problem.

Then I changed the name of the ForeignKey field to match, and again was asked by Makemigrations to confirm that I wanted to change the name. Migrate than made the change.

So I took this in two steps without any special file editing. I did get errors at first because I forgot to change the admin.py file, as mentioned by @wasibigeek.


回答 4

我也遇到了v.thorey所描述的问题,发现他的方法非常有用,但可以凝结为更少的步骤,实际上是步骤5至8,如Fiver所描述的,而没有步骤1-4,只是步骤7需要更改为在步骤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

完成了

PS我已经在Django 1.9上尝试过这种方法

I also faced the problem as v.thorey described and found that his approach is very useful but can be condensed into fewer steps which are actually step 5 to 8 as Fiver described without step 1 to 4 except that step 7 needs to be changed as my below step 3. The overall steps are as follow:

Step 1: Edit the related field names in 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()

Step 2: Create an empty migration

python manage.py makemigrations --empty myapp

Step 3: Edit the Migration class in the migration file created in Step 2

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')
]

Step 4: Apply the migration

python manage.py migrate

Done

P.S. I’ve tried this approach on Django 1.9


回答 5

我正在使用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

它为我重命名并将所有现有数据迁移到新的命名表。

I am using Django version 1.9.4

I have follow the following steps:-

I have just rename the model oldName to NewName Run python manage.py makemigrations. It will ask you for Did you rename the appname.oldName model to NewName? [y/N] select Y

Run python manage.py migrate and it will ask you for

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

appname | oldName
appname | NewName

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’.

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

It rename and migrate all existing data to new named table for me.


回答 6

不幸的是,我发现了重命名迁移的问题(每个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复制到Bar(包括idFoo)

  1. 可选的优化(如果需要更大的表)

提交B :(不要着急,整个团队迁移后都要做)

  1. 旧型号的安全降落 Foo

进一步清理:

  • 壁球迁徙

Django中的错误:

Unfortunately, I found problems (each django 1.x) with rename migration which leave old table names in the database.

Django doesn’t even try anything on the old table, just rename his own model. The same problem with foreign keys, and indices in general – changes there are not tracked properly by Django.

The simplest solution (workaround):

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

The real solution (an easy way to switch all indices, constraints, triggers, names, etc in 2 commits, but rather for smaller tables):

commit A:

  1. create the same model as the old one
# deprecated - TODO: TO BE REMOVED
class Foo(model.Model):
    ...

class Bar(model.Model):
    ...
  1. switch code to work with new model Bar only. (including all relations on the schema)

In migration prepare RunPython, which copy data from Foo to Bar (including id of Foo)

  1. optional optimization (if needed for greater tables)

commit B: (no rush, do it when an entire team is migrated)

  1. safe drop of the old model Foo

further cleanup:

  • squash on migrations

bug in Django:


回答 7

只是想确认并添加ceasaro评论。Django 2.0现在似乎可以自动执行此操作。

我在Django 2.2.1上,我所要做的只是重命名模型并运行makemigrations

在这里,它询问我是否已将特定的类从重命名AB,我选择是,然后进行了迁移,并且一切似乎都可以正常工作。

注意我没有在project / migrations文件夹内的任何文件中重命名旧模型名称。

Just wanted to confirm and add upon ceasaro comment. Django 2.0 seems to do this automatically now.

I’m on Django 2.2.1, all I had to do what to rename the model and run makemigrations.

Here it asks if I had renamed the specific class from A to B, i chose yes and ran migrate and all seems to work.

Note I did not rename the old model name in any files inside the project/migrations folder.


回答 8

我需要重命名几个表。但是Django仅注意到一种模型重命名。发生这种情况是因为Django反复遍历添加的模型,然后删除了模型。对于每一对,它会检查它们是否属于同一应用,并且具有相同的字段。只有一个表没有要重命名的表的外键(您记得,外键包含模型类名称)。换句话说,只有一个表没有字段更改。这就是为什么它被注意到。

因此,解决方案是一次重命名一个表,在中更改模型类名称models.py,可能是views.py,然后进行迁移。之后,检查您的代码是否有其他引用(模型类名称,相关(查询)名称,变量名称)。如果需要,请进行迁移。然后,有选择地将所有这些迁移合并为一个(确保也复制导入)。

I needed to rename a couple of tables. But only one model rename was noticed by Django. That happened because Django iterates over added, then removed models. For each pair it checks if they’re of the same app and have identical fields. Only one table had no foreign keys to tables to be renamed (foreign keys contain model class name, as you remember). In other words, only one table had no field changes. That’s why it was noticed.

So, the solution is to rename one table at a time, changing model class name in models.py, possibly views.py, and making a migration. After that inspect your code for other references (model class names, related (query) names, variable names). Make a migration, if needed. Then, optionally combine all these migrations into one (make sure to copy imports as well).


回答 9

我会用@ceasaro的话,对他对这个答案的评论。

较新版本的Django可以检测到更改并询问已完成的操作。我还要补充一点,Django可能会混合一些迁移命令的执行顺序。

这将是明智的,适用小的变化和运行makemigrations以及migrate如果发生错误的迁移文件进行编辑。

某些行的执行顺序可以更改,以免出错。

I would make @ceasaro words, mine on his comment on this answer.

Newer versions of Django can detect changes and ask about what was done. I also would add that Django might mix the order of execution of some migration commands.

It would be wise to apply small changes and run makemigrations and migrate and if the error occurs the migration file can be edited.

Some lines order of execution can be changed to avoid erros.


回答 10

如果您使用的是像PyCharm这样的优秀IDE,则可以右键单击模型名称并进行重构->重命名。这免除了您遍历引用该模型的所有代码的麻烦。然后运行makemigrations并进行迁移。Django 2+只会确认名称更改。

If you are using a good IDE like PyCharm you can right click on the model name and do a refactor -> rename. This saves you the trouble of going through all your code that references the model. Then run makemigrations and migrate. Django 2+ will simply confirm name change.


回答 11

我将Django从版本10升级到版本11:

sudo pip install -U Django

-U用于“升级”),它解决了问题。

I upgraded Django from version 10 to version 11:

sudo pip install -U Django

(-U for “upgrade”) and it solved the problem.