假设我有以下基本型号:
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()
尝试进行迁移和迁移会引发以下错误
课堂上的“超级英雄”中的“本地字段u'gender”与基类“人类”中名字相似的字段发生冲突
如何在不修改数据库的情况下切换到抽象类来保留所有迁移?
答案 0 :(得分:3)
由于Django将模型保存到数据库的方式引发了错误。从基础模型human
继承的所有模型在其自己的表中都没有所有human
个字段。相反,它们只有自己的字段和外键,它们将它们链接到human
表中的相应行。但是当你从抽象类继承时,所有字段都直接保存到模型的表中。因此,当我尝试将human
类更改为abstract=True
并在superhero
类中继承它时,Django尝试从human
表中的superhero
表创建所有字段,仍然有一个外键到现有的人类条目,字段名称完全相同。
按照此说明生成所需结果,但遗憾的是会销毁human
superhero
和villain
型号的所有条目
superhero
和villain
模型,以便Django删除它们superhero
和villain
表abstract=True
班级human
human
表,因为它现在是一个抽象类superhero
和villain
模型villain
class superhero
和human
表
醇>
就是这样。
P.S。为什么我需要转向抽象类?因为我想使用villains
参数使我的所有superheroes
和unique_together
唯一,这会产生一些数据库级限制。为了实现这一点,所有superhero
字段都必须在一个表中。现在它有效。
答案 1 :(得分:0)
这是一个老问题,但答案为我付出了很多努力。我只是想补充一些东西。
当使模型类从抽象模型继承时,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
这可以节省您评论大量代码。如果要将数据保存在数据库表中,则可以使用dumpdata
和loaddata
。
TLDR
这不是步骤指南的一个步骤,需要使用Django的经验。简而言之,你必须: