django model去掉unique_together报错的解决方案

事情是这样的,我有一个存储考试的表

class Exam(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)

 class Meta:
 unique_together = ('category', 'date')

category 表示考试的类型, date 表示考试的日期。建表的时候考虑到一个类型的考试在同一个应该只有一个考试,所以就加了一个 unique_together 。但是由于业务需要,这个 unique_together 不需要了。

用过 django 的人都知道,这不是个大问题,删掉 unique_together 的代码,然后 makemigrations 呗,确实,我就这么做了。但是当我 migrate 的时候却报错了,错误如下:

代码如下:

django.db.utils.OperationalError: (1553, "Cannot drop index 'insurance_exam_category_id_a430e581_uniq': needed in a foreign key constraint")

数据库不让我删除这个 index ,并且告诉我有一个 外键约束 用到了这个它。我就奇怪了,category是外键没错,但是我这个是 unique_together 啊,怎么可能有哪个外键用到了它呢?

没办法,我只能到数据库里寻找答案, show create table exam ,输出如下:

| insurance_exam | CREATE TABLE `insurance_exam` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(128) NOT NULL,
 `date` date NOT NULL,
 `created_at` datetime(6) NOT NULL,
 `updated_at` datetime(6) NOT NULL,
 `category_id` int(11) NOT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `insurance_exam_category_id_a430e581_uniq` (`category_id`,`date`),
 CONSTRAINT `insurance_exam_category_id_a2238260_fk_insurance_category_id` FOREIGN KEY (`category_id`) REFERENCES `insurance_category` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1062 DEFAULT CHARSET=utf8mb4 |

可以看到 UNIQUE KEY 那一行就是 unique_together ,下面一行是 category 外键。没有其他东西了啊,到底哪个外键用到了我们的 unique_together

外键只能是 category 了,也没有别的外键啊。到底是怎么回事呢?

原因是这样的: 在Mysql中外键会自动在表上添加一个index ,也就说如果没有unique_together,我们的表应该是这样的:

| insurance_exam | CREATE TABLE `insurance_exam` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(128) NOT NULL,
 `date` date NOT NULL,
 `created_at` datetime(6) NOT NULL,
 `updated_at` datetime(6) NOT NULL,
 `category_id` int(11) NOT NULL,
 PRIMARY KEY (`id`),
 KEY `category_id` (`category_id`),
 CONSTRAINT `insurance_exam_category_id_a2238260_fk_insurance_category_id` FOREIGN KEY (`category_id`) REFERENCES `insurance_category` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1062 DEFAULT CHARSET=utf8mb4 |

但是因为有了 unique_together unique_key ,并且 category 在联合索引的左边,根据 最左前缀 原则, category 的索引就有了,所以就不会另外建索引,这个时候 category 的外键约束就依赖了这个 unique_key ,所以删除的时候会出现那样的报错。

机智的小伙伴应该想到了,如果我们要去掉 unique_together ,我们可以将 category KEY 加回去,这样就可以将 unique_together 删掉了。 sql 如下:

alter table exam add index(category_id);

这样,migrate就能成功了。

(0)

相关推荐

  • Django基础之Model操作步骤(介绍)

    一.数据库操作 1.创建model表 基本结构: #coding:Utf8 from django.db import models class userinfo(models.Model): #如果没有models.AutoField,默认会创建一个id的自增列 name = models.CharField(max_length=30) email = models.EmailField() memo = models.TextField() 字段解释: 1.models.AutoField

  • Django中模型Model添加JSON类型字段的方法

    本文实例讲述了Django中模型Model添加JSON类型字段的方法.分享给大家供大家参考.具体如下: Django里面让Model用于JSON字段,添加一个JSONField自动类型如下: class JSONField(models.TextField): __metaclass__ = models.SubfieldBase description = "Json" def to_python(self, value): v = models.TextField.to_pytho

  • django模型中的字段和model名显示为中文小技巧分享

    简单方法: models.py 复制代码 代码如下: class IceCreamBar(models.Model):     title = models.CharField(max_length=200,db_index=True,verbose_name="名称")         shell = models.CharField(max_length=100,verbose_name='外皮')         filling = models.CharField(max_le

  • 浅谈django model的get和filter方法的区别(必看篇)

    django的get和filter方法是django model常用到的,搞清楚两者的区别非常重要. 为了说明它们两者的区别定义2个models class Student(models.Model): name = models.CharField('姓名', max_length=20, default='') age = models.CharField('年龄', max_length=20, default='') class Book(models.Model): student =

  • django model去掉unique_together报错的解决方案

    事情是这样的,我有一个存储考试的表 class Exam(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(au

  • Django migrate报错的解决方案

    前言 在讲解如何解决migrate报错原因前,我们先要了解migrate做了什么事情,migrate:将新生成的迁移脚本.映射到数据库中.创建新的表或者修改表的结构. 问题1:migrate怎么判断哪些迁移脚本需要执行? 它会将代码中的迁移脚本和数据库中django_migrations中的迁移脚本进行对比,如果发现数据库中,没有这个迁移脚本,那么就会执行这个迁移脚本. 问题2:migrate做了什么事情 将相关的迁移脚本翻译成SQL语句,在数据库中执行这个SQL语句. 如果这个SQL语句执行没

  • SpringBoot集成MybatisPlus报错的解决方案

    这篇文章主要介绍了SpringBoot集成MybatisPlus报错的解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 问题 启动的时候总是报如下错误: java.lang.annotation.AnnotationFormatError: Invalid default: public abstract java.lang.Class 解决方案 需要一个mybatis-spring-boot-starter的包,在pom文件加上之后,完

  • 基于Django实现日志记录报错信息

    这篇文章主要介绍了基于Django实现日志记录报错信息,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 当服务器500错误的时候,普通日志只会记录一行500的request信息,并不会记录详细的报错定位 [ERROR] 2019-06-12 15:07:03,597 "GET /api/v1/test/ HTTP/1.1" 500 74196 需要添加一个在日志中记录详细错误信息的middleware # -*- coding: UTF

  • 解决Django提交表单报错:CSRF token missing or incorrect的问题

    1.在Django提交表单时报错:Django提交表单报错: CSRF token missing or incorrect 具体报错页面如下: 2.有道词典翻译后如下: 通常,当存在真正的跨站点请求伪造时,或者Django的CSRF机制没有被正确使用时,就会出现这种情况.至于邮递表格,你须确保: 您的浏览器正在接受cookie. 视图函数将一个请求传递给模板的呈现方法. 在模板中,每个POST表单中都有一个{% csrf_token %}模板标记,目标是一个内部URL. 如果您没有使用Csrf

  • mybatis不加@Parm注解报错的解决方案

    我的idea版本2017.3.4,低版本貌似不会加上这个配置,idea高版本会 补充知识:Mybatis传多个参数的问题 及MyBatis报错 Parameter '0' not found. Available parameters are [arg1, arg0, param1 问题 对于使用Mybatis ,传多个参数,我们可以使用对象封装外,还可以直接传递参数 对象的封装,例如查询对象条件basequery对象 <select id="getProductByProductQuer

  • 启动springboot应用因未配置数据库报错的解决方案

    目录 启动springboot应用因未配置数据库报错 描述 解决方案 springboot 1.5.8.RELEASE 版本启动报错 起因 错误排查 解决方法 启动springboot应用因未配置数据库报错 描述 创建一个全新的springboot项目,第一次启动时报错,具体错误信息如下所示: Error starting ApplicationContext. To display the conditions report re-run your application with 'debu

  • Maven依赖junit @Test报错的解决方案

    目录 Maven依赖junit@Test报错 现象 解决方案 idea添加junit的maven依赖后,使用@Test.@Before.@After仍报错 maven中的依赖配置如下 Maven依赖junit @Test报错 现象 解决方案 测试文件夹标记使用错啦,test 表示junit的jar包只能在标记为 Test Sources Root 的文件夹下被调用,调整一下就OK了 如下图: idea添加junit的maven依赖后,使用@Test.@Before.@After仍报错 一般该问题

  • npm i报错以及解决方案实战案例

    目录 报错案例1 报错案例2 报错案例3 报错案例4 报错案例5 总结 报错案例1 npm ERR! Cannot read properties of null (reading 'pickAlgorithm') 解决方案:清理缓存后再次安装 npm cache clear --force 报错案例2 npm ERR! gyp info it worked if it ends with ok ... npm ERR! gyp ERR! cwd C:\...\node_modules\node

  • Luckysheet 在vue中离线使用及引入报错的解决方案(推荐)

    目录 1.git下载源码运行打包dist 2.将dist文件引入项目 3.应用 4.常见报错 1.git下载源码运行打包dist git 源码地址:https://github.com/mengshukeji/Luckysheet 下载好源码之后执行 npm install npm install gulp -g //跑去源码看看正常与否 npm run dev //如果正常执行打包 npm run build 打包结束后在目录下找到 dist 文件 2.将dist文件引入项目 将dist离线包

随机推荐