Django不会迁移,因为一个模型曾经是子类 [英] Django won't migrate because one model used to be a subclass
问题描述
我正在Ubuntu 18.04上使用Django 3.0.4和MySQL 5.7.
我有一个模型 Apples
.我创建了第二个模型 BadApples
作为其子类:
#models.py苹果类(models.Model):#个栏位BadApples(Apples)类:经过
我运行了迁移,该迁移成功完成了.
然后,我认为子类"方法无效,并且 BadApples
应该是其自己的模型.我改写了这样的模型:
#models.py苹果类(models.Model):#个栏位BadApples(models.Model)类:#个栏位
当我尝试运行迁移时,遇到以下错误:
MySQLdb._exceptions.OperationalError:(1090,您不能使用ALTER TABLE删除所有列;请改用DROP TABLE")
据我所知,将 BadApples
从一种形式迁移到另一种形式涉及更改其所有列.Django并没有删除表并重新创建它,而是仅使用ALTER TABLE命令,该命令在尝试删除原始 BadApples
的最后一列时会引发MySQL错误.这似乎与此错误有关,据说该错误已于两年前修复,但显然没有完全解决./p>
要解决此错误,我的想法是从其余的 models.py
中删除 BadApples
以及所有对 BadApples
的引用.代码(在本例中为 views.py
和 admin.py
).然后,我将运行一个迁移,由于它不再存在,因此会完全删除 BadApples
表,然后可以将其重新创建为单独的迁移.
相反,在确认代码中没有任何地方存在 BadApples
模型的痕迹后,运行 makemigrations
会引发以下错误:
django.core.exceptions.FieldError:类"BadApples"中的本地字段"id"与基类"Apples"中具有相同名称的字段发生冲突.
当我最初创建 BadApples
作为 Apples
的子代时,其表没有 id
字段,因为其数据存储在 Apples
表.在将其更改为独立模型之后,现在为其表分配了一个 id
字段.Django保留了 BadApples
作为 Apples
的子代的一些记忆,但它认为这是冲突.
为解决此问题,我在开始创建 BadApples
之前立即恢复了迁移.迁移成功完成:
$ python3 manage.py迁移AppName 0012_auto_some_number要执行的操作:目标特定的迁移:来自AppName的0012_auto_some_number运行迁移:渲染模型状态...完成取消应用AppName.0013_badapples ...确定
这时,在我的代码中的任何地方都没有引用 BadApples
,并且模型处于一个甚至根本不存在 BadApples
的位置.但是,当我尝试运行迁移时(未对 models.py
进行进一步更改),我仍然会收到错误消息
django.core.exceptions.FieldError:类"BadApples"中的本地字段"id"与基类"Apples"中具有相同名称的字段发生冲突.
Django专注于 BadApples
曾经存在并且是 Apples
的子类的想法.我该如何取消固定?
您要执行的此类操作非常复杂,以致Django Migrate无法推断您要执行的操作.在这种情况下,您应该编写一个自定义迁移来处理它可以向前迁移数据库.在此迁移中,您可以告诉它正确删除表并创建一个新表.
在迁移文件主题中,有一个显示 migrations.DeleteModel()
的示例> 方法.
导入迁移,模型类Migration(migrations.Migration):依赖关系= [('migrations','0001_initial')]操作= [migrations.DeleteModel('Tribble'),migrations.AddField('Author','rating',models.IntegerField(default = 0)),]
I'm using Django 3.0.4 with MySQL 5.7 on Ubuntu 18.04.
I have a model Apples
. I created a second model BadApples
as a subclass of it:
# models.py
class Apples(models.Model):
# fields
class BadApples(Apples):
pass
I ran the migration, which completed successfully.
Then, I decided that the 'subclass' approach wasn't working and that BadApples
should be its own model. I rewrote the models like this:
# models.py
class Apples(models.Model):
# fields
class BadApples(models.Model):
# fields
When I tried to run the migration, I ran into the following error:
MySQLdb._exceptions.OperationalError: (1090, "You can't delete all columns with ALTER TABLE; use DROP TABLE instead")
As best I can tell, migrating BadApples
from one form to the other involves changing all of its columns. Instead of dropping the table and recreating it, Django uses ALTER TABLE commands only, which throws the MySQL error when it attempts to remove the last column of the original BadApples
. This seems related to this bug, purportedly fixed over two years ago, but evidently not fully.
To work around this bug, my idea was to remove BadApples
from models.py
and all references to BadApples
from the rest of the code (in this case, views.py
and admin.py
). Then I'd run a migration, which would drop the BadApples
table entirely because it no longer exists, and then I could recreate it as a separate migration.
Instead, after confirming that there is no trace of the BadApples
model anywhere in my code, running makemigrations
throws this error:
django.core.exceptions.FieldError: Local field 'id' in class 'BadApples' clashes with field of the same name from base class 'Apples'.
When I originally created BadApples
as a child of Apples
, its table had no id
field because its data was stored in the Apples
table. After I changed it to be an independent model, its table now gets assigned an id
field. Django retains some memory of BadApples
being a child of Apples
, however, and it sees this as a conflict.
To try to fix this, I reverted to the migration immediately before I ever created BadApples
in the first place. This migration completed successfully:
$ python3 manage.py migrate AppName 0012_auto_some_number
Operations to perform:
Target specific migration: 0012_auto_some_number, from AppName
Running migrations:
Rendering model states... DONE
Unapplying AppName.0013_badapples... OK
At this point, there is NO reference to BadApples
anywhere in my code, and the models are at a point where BadApples
has never even existed. Yet, when I try to run a migration (with no further changes to models.py
), I still get the error
django.core.exceptions.FieldError: Local field 'id' in class 'BadApples' clashes with field of the same name from base class 'Apples'.
Django is fixated on the idea that BadApples
used to exist and be a subclass of Apples
. How do I un-fixate it?
This type of operation you're trying to perform is sufficiently complicated that Django Migrate can't infer what you're trying to do. In situations like these you should write a custom migration to handle how it can migrate the database forward. In this migration you can tell it to properly drop the table and create a new one.
In the Migration Files topic there is an example that shows the migrations.DeleteModel()
method.
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [('migrations', '0001_initial')]
operations = [
migrations.DeleteModel('Tribble'),
migrations.AddField('Author', 'rating', models.IntegerField(default=0)),
]
这篇关于Django不会迁移,因为一个模型曾经是子类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!