django model去掉unique_together报错的解决方案
事情是这样的,我有一个存储考试的表
classExam(models.Model): category=cached_fields.ForeignKeyField(Category) name=models.CharField(max_length=128) date=models.DateField() created_at=models.DateTimeField(auto_now_add=True) updated_at=models.DateTimeField(auto_now=True) classMeta: unique_together=('category','date')
category表示考试的类型,date表示考试的日期。建表的时候考虑到一个类型的考试在同一个应该只有一个考试,所以就加了一个unique_together。但是由于业务需要,这个unique_together不需要了。
用过django的人都知道,这不是个大问题,删掉unique_together的代码,然后makemigrations呗,确实,我就这么做了。但是当我migrate的时候却报错了,错误如下:
django.db.utils.OperationalError:(1553,"Cannotdropindex'insurance_exam_category_id_a430e581_uniq':neededinaforeignkeyconstraint")
数据库不让我删除这个index,并且告诉我有一个外键约束用到了这个它。我就奇怪了,category是外键没错,但是我这个是unique_together啊,怎么可能有哪个外键用到了它呢?
没办法,我只能到数据库里寻找答案,showcreatetableexam,输出如下:
|insurance_exam|CREATETABLE`insurance_exam`( `id`int(11)NOTNULLAUTO_INCREMENT, `name`varchar(128)NOTNULL, `date`dateNOTNULL, `created_at`datetime(6)NOTNULL, `updated_at`datetime(6)NOTNULL, `category_id`int(11)NOTNULL, PRIMARYKEY(`id`), UNIQUEKEY`insurance_exam_category_id_a430e581_uniq`(`category_id`,`date`), CONSTRAINT`insurance_exam_category_id_a2238260_fk_insurance_category_id`FOREIGNKEY(`category_id`)REFERENCES`insurance_category`(`id`) )ENGINE=InnoDBAUTO_INCREMENT=1062DEFAULTCHARSET=utf8mb4|
可以看到UNIQUEKEY那一行就是unique_together,下面一行是category外键。没有其他东西了啊,到底哪个外键用到了我们的unique_together?
外键只能是category了,也没有别的外键啊。到底是怎么回事呢?
原因是这样的:在Mysql中外键会自动在表上添加一个index,也就说如果没有unique_together,我们的表应该是这样的:
|insurance_exam|CREATETABLE`insurance_exam`( `id`int(11)NOTNULLAUTO_INCREMENT, `name`varchar(128)NOTNULL, `date`dateNOTNULL, `created_at`datetime(6)NOTNULL, `updated_at`datetime(6)NOTNULL, `category_id`int(11)NOTNULL, PRIMARYKEY(`id`), KEY`category_id`(`category_id`), CONSTRAINT`insurance_exam_category_id_a2238260_fk_insurance_category_id`FOREIGNKEY(`category_id`)REFERENCES`insurance_category`(`id`) )ENGINE=InnoDBAUTO_INCREMENT=1062DEFAULTCHARSET=utf8mb4|
但是因为有了unique_together的unique_key,并且category在联合索引的左边,根据最左前缀原则,category的索引就有了,所以就不会另外建索引,这个时候category的外键约束就依赖了这个unique_key,所以删除的时候会出现那样的报错。
机智的小伙伴应该想到了,如果我们要去掉unique_together,我们可以将category的KEY加回去,这样就可以将unique_together删掉了。sql如下:
altertableexamaddindex(category_id);
这样,migrate就能成功了。