问题描述
我对Django开发非常陌生。我正在使用MysqL创建的旧数据库。现在,我面临着Django迁移的问题。我有几个使用外键引用另一个表的表。现在,如果我允许Django使用外键管理这些表,那么Django会尝试在make-migrations和migration命令期间重新创建外键字段。即使字段已经在那里。此外,如果我不允许Django管理这些表,则Django将与数据库完美配合。
Models.py
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.db.models.signals import pre_save
from chooseright.utils import unique_slug_generator
class StoreTable(models.Model):
store_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=45,blank=True,null=True)
slug = models.SlugField(max_length=45,null=True)
category = models.ForeignKey(CategoryTable,on_delete=models.CASCADE,null=True)
brand = models.ForeignKey(BrandTable,models.DO_nothing,null=True)
class Meta:
managed = True
db_table = 'store_table'
verbose_name = _("Store")
verbose_name_plural = _("Stores")
def __str__(self):
return self.name
迁移代码
from django.db import migrations,models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('core','0009_auto_20200820_1258'),]
operations = [
migrations.RenameField(
model_name='storetable',old_name='store_name',new_name='name',),migrations.AddField(
model_name='storetable',name='brand',field=models.ForeignKey(blank=True,null=True,on_delete=django.db.models.deletion.DO_nothing,to='core.BrandTable'),name='category',on_delete=django.db.models.deletion.CASCADE,to='core.CategoryTable'),]
尝试迁移时的跟踪
File "C:\Users\Usama\dev\Django Projects\lib\site-packages\MysqLdb\connections.py",line 259,in query
_MysqL.connection.query(self,query)
django.db.utils.OperationalError: (1060,"Duplicate column name 'brand_id'")
现在,我知道Django正在尝试重新创建外键字段。但是由于它是旧数据库,所以我不明白为什么会这样。
解决方法
今天我遇到了这个问题,当时我不得不对一个使用 Django 1.11 的真正遗留项目进行小改动。我相信您遇到了this bug。 comment 7 中提到的解决方法对我有用。该错误尚未解决,因此可能仍会在较新版本的 Django 中发生。
基本上,您将执行以下步骤来解决问题:
- 当您最初运行
inspectdb
并创建模型时,Django 将使用managed = False
创建模型。 - 在
models.py
中,您应该在进行迁移之前临时设置managed = True
。 - 然后使用
manage.py makemigrations
创建迁移。暂时不要运行迁移。 - 检查生成的迁移文件并手动将所有
managed: True
更新为manage: False
。 - 最后回到您的
models.py
并将任何managed = True
恢复为managed = False
。 - 现在使用
manage.py migrate
运行迁移。
完成上述步骤后,您应该通过执行以下操作将非托管模型转换为托管模型:
- 在
models.py
中,您现在将永久设置managed = True
或只是完全删除managed
行,因为它默认为True
。 - 使用
manage.py makemigrations
创建迁移。 - 使用
manage.py migrate
运行迁移。
此时您可以自由地对模型进行进一步更新,您会注意到 Django 不再尝试重新创建已经存在的 ForeignKey
。
根据文档here,您需要告诉django不要管理您的模型。组
managed=False
,如果您不希望django通过其迁移创建或修改任何内容。