Django 数据库迁移报错问题记录
Django迁移报错问题记录
问题现象
变动模型后,执行migrate命令将模型变动应用于数据库时,出现如下报错:django.core.exceptions.FieldDoesNotExist。
问题解决
首先查找了Component模型中name字段的应用情况,未发现该字段作为其他模型的外键。
尝试先不删除Component模型的name字段,先应用模型中其他字段的变更,不报错,再次删除name字段,迁移数据库不报错。
查看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')]), ),
问题分析
对比原有模型与变动后的模型,变动前后的模型中,对字段和联合索引均做了操作,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)修改迁移文件中联合索引和字段的变更顺序,在删除字段前先修改联合索引,然后执行字段的删除。