【问题标题】:How to convert django model to abstract model if it already has related classes如果已经有相关类,如何将 django 模型转换为抽象模型
【发布时间】:2016-02-16 18:11:37
【问题描述】:

假设我有以下基本模型:

class human(models.Model):
   gender = models.BooleanField()
   age = models.IntegerField()
   name = models.CharField(max_length=200)

还有两个继承它的模型:

class superhero(human):
   can_fly = models.BooleanField()

class villain(human):
   fingerprint = models.ImageField()

在我的开发过程中的某个时候,我意识到我实际上并不直接需要人类课程。我只需要它是一组超级英雄和反派模型的模板参数。如果现在我去人类Meta 类并设置abstract=True 并像这样更改我的模型:

class human(models.Model):
   gender = models.BooleanField()
   age = models.IntegerField()
   name = models.CharField(max_length=200)

   class Meta:
       abstract = True

class superhero(human):
   can_fly = models.BooleanField()

class villain(human):
   fingerprint = models.ImageField()

尝试进行迁移和迁移会引发以下错误

'superhero' 类中的本地字段 u'gender' 与基类 'human' 中类似名称的字段发生冲突

如何在不直接修改数据库的情况下切换到抽象类来保留所有迁移?

【问题讨论】:

    标签: python django django-models abstract-class django-migrations


    【解决方案1】:

    这是一个老问题,但答案为我节省了很多精力。我只是想补充一点。

    当使模型类继承自抽象模型时,Django 迁移将删除该模型。

    MyModel(models.Model):
        # some fields to be inherited later from the abstract model
        author = models.ForeignKey('auth.User')
        # other fields specific to this model
    

    现在如果你创建一个抽象模型:

    MyAbstractModel(models.Model):
        # fields to be used by children classes
    
        class Meta:
            abstract = True
    

    让你的模型继承它:

    MyModel(MyAbstractModel):
        author = models.ForeignKey('auth.User')
        # other fields specific to this model
    

    如果你在你的应用程序上运行 makemigrations 并迁移,Django 将删除该模型并删除对应的数据库表。

    您可以通过注释掉该模型的代码来超越 Django。 Django 将删除它并带来所有其他后果。现在您可以取消注释代码并再次运行迁移,Django 将再次创建数据库表。

    但是,您可能需要您的管理员、视图、表单等来导入您的模型。这意味着迁移将引发错误,因为找不到该类。您必须在导入模型的所有文件中注释掉代码。

    更简单的方法是跳过注释并手动编写所需的迁移:

    from __future__ import unicode_literals
    
    from django.db import migrations
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            # app_label should be your app
            # and 000x_the_last_migration is the name of the migration
            # it depends on, usually the last one
            ('app_label', '000x_the_last_migration'),
        ]
    
        operations = [
            # do this for all ForeignKey, ManyToManyField, OneToOneField
            # where model_name is obviously the model name and name is the
            # field name
            migrations.RemoveField(
                model_name='mymodel',
                name='author',
            ),
            # finally delete the model
            migrations.DeleteModel(
                name='MyModel',
            ),
        ]
    

    现在您可以运行迁移了:

    python manage.py migrate app_label
    

    稍后从抽象模型继承(参见上面的代码,第 3 块)并进行新的迁移:

    python manage.py makemigrations app_label
    

    这应该可以节省您注释掉大量代码的时间。如果要将数据保存在DB表中,则可以使用dumpdataloaddata

    TLDR

    这不是分步指南,需要有 Django 经验。简而言之,您必须:

    1. 创建抽象模型
    2. 为必须从抽象模型继承的模型手动编写迁移
    3. 运行迁移(这会删除包含所有条目的数据库表!)
    4. 从抽象模型继承
    5. 运行 makemigrations 并迁移

    【讨论】:

      【解决方案2】:

      所以在再次阅读文档后,我找到了解决方案:

      由于 Django 将模型保存到数据库的方式而引发错误。从基本模型human 继承的所有模型在它们自己的表中都没有所有human 字段。相反,它们只有自己的字段和将它们链接到human 表中相应行的外键。但是,当您从抽象类继承时,所有字段都直接保存到模型的表中。因此,当我尝试将human 类更改为abstract=True 并在superhero 类中继承它时,Django 尝试从superhero 表中的human 表创建所有字段,该表仍然具有现有人工条目的外键字段名称完全相同。

      警告

      按照此说明操作将获得所需的结果,但不幸的是将销毁所有条目 human superherovillain 模型

      1. 评论 superherovillain 模型以便 Django 删除它们
      2. 进行迁移并迁移,以便删除 superherovillain
      3. human类中设置abstract=True
      4. 进行迁移并再次迁移。这将删除 human 表,因为它现在是一个抽象类
      5. 取消注释 superherovillain 模型
      6. 进行迁移并迁移。这将创建 villainsuperhero 表,其中包含 human 类中的所有字段

      就是这样。

      附:为什么我需要转到抽象类?因为我想使用unique_together 参数使我所有的villainssuperheroes 唯一,这会产生一些数据库级别的限制。为了使这成为可能,所有superhero 字段必须在一个表中。现在可以了。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-13
      • 1970-01-01
      • 1970-01-01
      • 2016-01-10
      • 1970-01-01
      • 2018-03-13
      • 1970-01-01
      相关资源
      最近更新 更多