Skip to content

Django 数据库迁移报错问题记录

710字约2分钟

PythonDjango

2023-01-05

Django迁移报错问题记录

问题现象

变动模型后,执行migrate命令将模型变动应用于数据库时,出现如下报错:django.core.exceptions.FieldDoesNotExist。

Snipaste_2022-12-30_14-26-36

问题解决

  1. 首先查找了Component模型中name字段的应用情况,未发现该字段作为其他模型的外键。

  2. 尝试先不删除Component模型的name字段,先应用模型中其他字段的变更,不报错,再次删除name字段,迁移数据库不报错。

    image-20221230143312379

  3. 查看django生成的迁移文件,发现其修改联合索引的操作位于删除字段操作之后,尝试将修改联合索引的操作移动至删除字段之前,执行数据库迁移操作,不报错。

    	# django模型迁移文件中的部分代码	
        migrations.RemoveField(
            model_name='component',
            name='abnormal_nodes',
        ),
        migrations.RemoveField(
            model_name='component',
            name='name',
        ),
        migrations.RemoveField(
            model_name='component',
            name='normal_nodes',
        ),
        migrations.RemoveField(
            model_name='component',
            name='status',
        ),
        migrations.RemoveField(
            model_name='component',
            name='sum_nodes',
        ),
        migrations.RemoveField(
            model_name='component',
            name='updated_at',
        ),
        migrations.RemoveField(
            model_name='component',
            name='version',
        ),
        migrations.AlterUniqueTogether(
            name='component',
            unique_together=set([('cluster', 'cmpnt_name')]),
        ),

    image-20221230143608671

问题分析

对比原有模型与变动后的模型,变动前后的模型中,对字段和联合索引均做了操作,Django根据模型变动生成的迁移文件中,对于字段的变动有新增、修改和删除,而对于联合索引的变动只有修改操作,因此应该是修改联合索引时,对联合索引的字段进行查找,而如上的操作则是查询不到的情况下出现的报错。

# 变动前的模型
class Component(models.Model):
    cluster = models.ForeignKey(Cluster)
    name = models.CharField(default='', max_length=50)
    version = models.CharField(default='', max_length=50)
    sum_nodes = models.IntegerField(null=True)
    normal_nodes = models.IntegerField(null=True)
    abnormal_nodes = models.IntegerField(null=True)
    status = models.BooleanField(blank=True)
    updated_at = models.DateTimeField(null=True)

    class Meta:
        unique_together = ("cluster", "name")
# 变动后的模型
class Component(models.Model):
    """
    集群组件信息表
    """
    cluster = models.ForeignKey(Cluster, db_index=True)
    cmpnt_name = models.CharField(max_length=50, default='', verbose_name='组件名称')
    cmpnt_version = models.CharField(max_length=50, default='', verbose_name='组件版本')
    extra_info = models.CharField(max_length=5000, default='')
    is_monitored = models.BooleanField(default=False, verbose_name='是否可监控')
    is_assigned = models.BooleanField(default=False, verbose_name='是否可分配')
    is_authorised = models.BooleanField(default=False, verbose_name='是否可授权')
    registed_by = models.CharField(max_length=50, default='', verbose_name='组件注册用户')
    registed_at = models.DateTimeField(auto_now=True, verbose_name='组件注册时间')
    updated_by = models.CharField(max_length=50, default='', verbose_name='组件更新用户')
    enabled_flag = models.BooleanField(default=True, verbose_name='组件是否启用')
    enabled_flag_updated_by = models.CharField(max_length=50, default='', verbose_name='组件启用修改用户')
    enabled_flag_updated_at = models.DateTimeField(null=True, verbose_name='组件启用修改时间')

    class Meta:
        unique_together = (("cluster", "cmpnt_name"))

该问题的解决有两种方案: (1)迁移的操作分为两次,第一次只修改不涉及联合索引模型字段,同时修改原有的联合索引。 (2)修改迁移文件中联合索引和字段的变更顺序,在删除字段前先修改联合索引,然后执行字段的删除。