【问题标题】:Django rename model. New django_content_type is created instead of renaming the old recordDjango 重命名模型。创建新的 django_content_type 而不是重命名旧记录
【发布时间】:2015-01-05 05:24:53
【问题描述】:

设置:

Django 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 实例,将其与Building 关联并保存:

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

现在我将 Buildings 重命名为 Building 并运行 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 行都不会被吹走?

【问题讨论】:

    标签: python django django-migrations


    【解决方案1】:

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

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

    # -*- 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)
        ]
    

    【讨论】:

    • 澄清一下,您运行makemigrations,然后使用新创建的迁移的依赖项创建此迁移,然后migrate 两者?
    • 很高兴它有帮助!这对我来说似乎是 Django 迁移中的一个错误的解决方法——如果它不在 Django bugtracker 中但我前几天找不到它,我会感到惊讶。如果不存在,我会尝试再次查看并报告错误。
    【解决方案2】:

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

    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-08-25
      • 1970-01-01
      • 2020-07-08
      • 2011-07-23
      • 2015-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-26
      相关资源
      最近更新 更多