1

设置:

姜戈 1.7 | Postgres 9.x

class Buildings(BaseModel):
    number = models.CharField(max_length=25)

class TestGeneric(models.Model):

    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey()

假设我创建了一个TestGeneric实例,将它与 a 关联Building并保存它:

TestGeneric.objects.create(content_object=Building.objects.first())

现在我重命名BuildingsBuilding并运行makemigrations. 提示我Did you rename the app.Buildings model to Building? [y/N]

我选择是。然后我运行migrate并得到:

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

app | buildings

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

无论我回答什么,Django 都会自动在django_content_type其中创建一个新行building作为名称和标签。有没有办法重命名,ContentType这样我的所有 TestGeneric 行都不会被吹走?

4

2 回答 2

1

我只是在一个项目中使用它;需要注意的是,如果您在尝试应用自动创建的模型重命名迁移之前创建迁移,这将毫无问题。

您需要更改应用名称、模型名称和之前的迁移以匹配您的设置;在此示例中,我们将模型的名称从 更改profilemember

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations
from django.conf import settings

sql = """UPDATE django_content_type
         SET name = 'member',
             model = 'member'
         WHERE name = 'profile' AND
               model = 'profile' AND
               app_label = 'open_humans';"""

reverse_sql = """UPDATE django_content_type
                 SET name = 'profile',
                     model = 'profile'
                 WHERE name = 'member' AND
                       model = 'member' AND
                       app_label = 'open_humans';"""


class Migration(migrations.Migration):

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ('open_humans', '0004_auto_20150106_1828'),
    ]

    operations = [
        migrations.RunSQL(sql, reverse_sql)
    ]
于 2015-01-06T21:02:16.763 回答
1

我可以分享为这个问题编写的迁移操作:

from django.db import migrations
from django.contrib.contenttypes.models import ContentType


class UpdateContentType(migrations.RunPython):
    '''Database migration operation to update a ContentType'''

    def _update_contenttype_func(self, old_app: str, old_model: str, new_app: str, new_model: str):
        def func(apps, schema_editor):
            ContentType.objects \
                .filter(app_label=old_app, model=old_model) \
                .update(app_label=new_app, model=new_model)
            ContentType.objects.clear_cache()
        return func

    def __init__(self, app: str, model: str, new_app: str = None, new_model: str = None):
        if new_app is None:
            new_app = app
        if new_model is None:
            new_model = model
        self.app = app
        self.model = model
        self.new_app = new_app
        self.new_model = new_model
        super().__init__(
            code=self._update_contenttype_func(
                old_app=app, old_model=model, new_app=new_app, new_model=new_model
            ),
            reverse_code=self._update_contenttype_func(
                old_app=new_app, old_model=new_model, new_app=app, new_model=model
            ),
        )

    def describe(self):
        return (f"Update ContentType {self.app}.{self.model}"
                f" to {self.new_app}.{self.new_model}")

每当重命名模型时,我都会编辑迁移文件并添加一个UpdateContentType操作:

from django.db import migrations
from apps.utils.migrations_util import UpdateContentType

class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0010_previous_migration'),
        ('contenttypes', '0002_remove_content_type_name'),
    ]

    operations = [
        migrations.RenameModel(old_name='OldModel', new_name='NewModel'),
        UpdateContentType(app='myapp', model='oldmodel', new_model='newmodel'),
    ]

于 2020-05-16T13:52:12.163 回答