Django不会迁移,因为一个模型曾经是子类 [英] Django won't migrate because one model used to be a subclass

查看:54
本文介绍了Django不会迁移,因为一个模型曾经是子类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在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()的示例> 方法.

django.db中的

 导入迁移,模型类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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆