Django migration 新增外键的坑
TL;DR
永远不要相信 makemigrations!
migrate 之前一定好好看看 migrate 了啥东西,必要时手动修改生成的 migrate 文件。
最好把db的更新与服务代码更新解耦
场景
先描述下场景:
现在有两个表,一个是 question,一个是 choice,其中 question 和 choice 是一对多的关系,其中 choice 表中会记录 question_id(此时不是外键约束)。
class Question(models.Model):content = models.CharField(max_length=256, blank=True, default='')class Choice(models.Model):content = models.CharField(max_length=256, default='')question_id = models.IntegerField(null=True)
现在我想把 question_id 改为外键,所以很自然的改写 model:
class Question(models.Model):content = models.CharField(max_length=256, blank=True, default='')class Choice(models.Model):content = models.CharField(max_length=256, default='')question = models.ForeignKey(Question, on_delete=models.DO_NOTHING)
然后快乐地执行 makemigration -> migrate,然后 choice 里面的 question_id 就全没了(实际上我还手贱加了个 default,导致都关联到 default 的 question 上了),然后第二天因为左脚先进办公室被开了。。。
原因
在自己的 demo 上复现了下。
问题出在 makemigrate 生成的文件上,解析出来的 operations 是先把 question_id 列 remove 掉(RemoveField),然后再加上(AddField)。。。
这样设计的思路我不是很懂,可能是有些 engine(比如SQLite)不支持对现有的表加外键?
解决
修改 migration 文件,把先 remove 再 add 的逻辑调整一下。
需要用到 migration.RunPython,migration 文件应该长成下边这样:
from django.db import migrations, models
import django.db.models.deletiondef duplicate_question_id(apps, schema_editor):Choice = apps.get_model("polls", "Choice")for c in Choice.objects.all():Question = apps.get_model("polls", "Question")q = Question.objects.get(id=c.question_id)c.question_cpy = qc.save()class Migration(migrations.Migration):# 一些必要的依赖,这里大概率不用改dependencies = []operations = [migrations.AddField(model_name="choice",name="question_cpy",# question_cpy 先把 question_id 列的数据 copy 过来field=models.ForeignKey(null=True,on_delete=django.db.models.deletion.DO_NOTHING,to="polls.question",),),migrations.RunPython(code=duplicate_question_id,reverse_code=migrations.RunPython.noop,# reverse_code 是 migrate 回退时会执行的操作# noop 方法是为了支持回退的空方法),migrations.RemoveField(model_name="choice",name="question_id",),migrations.RenameField(model_name="choice",old_name="question_cpy",new_name="question",),]
注意:你需要根据实际情况编写合适的代码,上面仅提供思路。
如果你是在sqlite上测试,可以正常 migrate,但是外键不会生效(因为 sqlite 默认关闭外键)。
如果在 mysql 上测试,应该是可以成功的(待验证)。
除了 RunPython 之外还可以用RunSQL,然后仔细确定SQL的合法性,个人感觉会更安全一些,毕竟直接操作 DB 的部分,普遍会认为潜在风险较高,会对相应动作有更高的敏感度。(不过最关键的还是要感知 makemigrations 其实不是个靠谱的东西)
又跟了下这个问题,发现在 AlterField 里面指定外键的 db_column,然后再 rename 成 model 里面指定的 name 即可实现上述需求,类似:
migrations.AlterField(model_name="choice",name="question_id",field=models.ForeignKey(name='question',to='polls.question',on_delete=django.db.models.deletion.DO_NOTHING,db_column='question_id',null=False),),migrations.RenameField(model_name="choice",old_name="question_id",new_name="question",)
这里还有些需要注意的地方,migration 整体上是通过 DDL 事务执行的,但是有些 SQL 引擎不支持DDL 事务(比如 MySQL),所以可能会出现 migrate 不成功然后无法回滚的情况(一个 migration 可能会对应两条 SQL 语句),需要关注。
避免
永远不要相信 makemigrations!
最好把db的更新与服务代码更新解耦
Django 还提供了 sqlmigrate 这个命令,可以看对应的 migrations 动作具体会解析成哪些 sql 语句执行,可以在 merge 之前把对应的 sql 语句进行一次 review。
推荐
migrate 其实分 code state 和 db state 两部分,可以把这两部分开设置:change field name with no db impact
相关文章:
Django migration 新增外键的坑
TL;DR 永远不要相信 makemigrations! migrate 之前一定好好看看 migrate 了啥东西,必要时手动修改生成的 migrate 文件。 最好把db的更新与服务代码更新解耦 场景 先描述下场景: 现在有两个表,一个是 question,一…...
相关系数(皮尔逊相关系数和斯皮尔曼相关系数)
本文借鉴了数学建模清风老师的课件与思路,可以点击查看链接查看清风老师视频讲解:5.1 对数据进行描述性统计以及皮尔逊相关系数的计算方法_哔哩哔哩_bilibili 注:直接先看 ( 三、两个相关系数系数的比较 ) 部分&#x…...
了解 Vite 插件
众所周知 Vite 是基于 Rollup 的构建工具,Vite 插件为了优化、扩展项目构建系统功能的工具。 比如 vite-plugin-eslint 为我们提供了代码分析的功能,帮助我们在开发过程中的风格一致性。 简单示例 本文中的示例是基于 Vite Vue3.x TypeScript 来实现…...
算法竞赛基础:C++双向链表的结构和实现(普通链表、List、静态链表)
算法竞赛基础:双向链表 本文将会介绍在算法竞赛中双向链表的几种使用方式,适合有一定基础的人阅读。 双向链表的结构 一般来说,普通的链表结构是这样的: struct node {int num;node *next; }next指针指向下一个链表ÿ…...
openssl3.2/test/certs - 019 - ca-nonca trust variants: +serverAuth, +anyEKU
文章目录 openssl3.2/test/certs - 019 - ca-nonca trust variants: serverAuth, anyEKU概述笔记 ca-nonca.pem from exp 016openssl3.2/test/certs - 019 - ca-nonca trust variants: serverAuth, anyEKUEND openssl3.2/test/certs - 019 - ca-nonca trust variants: serverAu…...
Unity SRP 管线【第五讲:URP烘培光照】
本节,我们将跟随数据流向讲解UEP管线中的烘培光照。 文章目录 一、URP烘培光照1. 搭建场景2. 烘培光照参数设置MixedLight光照设置:直观感受 Lightmapping Settings参数设置: 3. 我们如何记录次表面光源颜色首先我们提取出相关URP代码&#…...
Mysql运维篇(一) 日志类型
一路走来,所有遇到的人,帮助过我的、伤害过我的都是朋友,没有一个是敌人,如有侵权请留言,我及时删除。 一、mysql相关日志 首先,我们能接触到的,一般我们排查慢查询时,会去看慢查询日志。如果做过数据备份会恢复的,可能接触或用过BinLog。那还有其他的吗?对MySQL原理…...
【C语言】结构体与内存操作函数 总结
结构体 一、结构体简介 C 语言内置的数据类型,除了最基本的几种原始类型,只有数组属于复合类型,可以同时包含多个值,但是只能包含相同类型的数据,实际使用中并不够用。 实际使用中,主要有下面两种情况&a…...
第12章_集合框架(Collection接口,Iterator接口,List,Set,Map,Collections工具类)
文章目录 第12章_集合框架本章专题与脉络1. 集合框架概述1.1 生活中的容器1.2 数组的特点与弊端1.3 Java集合框架体系1.4 集合的使用场景 2. Collection接口及方法2.1 添加2.2 判断2.3 删除2.4 其它 3. Iterator(迭代器)接口3.1 Iterator接口3.2 迭代器的执行原理3.3 foreach循…...
C语言进阶——数据结构之链表(续)
前言 hello,大家好呀,我是Humble,本篇博客承接之前的C语言进阶——数据结构之链表 的内容(没看过的小伙伴可以从我创建的专栏C语言进阶之数据结构 找到那篇文章并阅读后在回来哦~),上次我们重点说了链表中…...
数据库课程设计-图书管理系统数据库设计
目录 一、实验目的 二、实验内容 三、实验要求 四、实验设计 4.1需求分析 4.1.1系统目标 4.1.2功能需求 4.1.3性能需求 4.14界面需求 4.2概念模型设计 4.2.1 实体及联系 4.2.2 E-R图 4.3 逻辑设计 4.3.1 E-R模型向关系模型的转换 4.3.2 数据库逻辑结构 4.3.3数据库模型函数依赖…...
【超简版,代码可用!】【0基础Python爬虫入门——下载歌曲/视频】
安装第三方模块— requests 完成图片操作后输入:pip install requests 科普: get:公开数据 post:加密 ,个人信息 进入某音乐网页,打开开发者工具F12 选择网络,再选择—>媒体——>获取URL【先完成刷新页面】 科…...
CommunityToolkit.Mvvm支持环境
引言 CommunityToolkit.Mvvm 包(又名 MVVM 工具包,以前称为 Microsoft.Toolkit.Mvvm)是一个现代、快速和模块化的 MVVM 库。 它是 .NET 社区工具包的一部分,其中一条原则是: 独立于平台和运行时 - .NET Standard 2.0…...
探讨品牌设计的本质,为企业形象注入活力!
品牌设计作为一个行业,首先需要明确行业的本质和意义。由于越来越多的咨询公司和营销公司对品牌有不同的理解和解释,因为他们服务的内容和专业水平不同,什么是品牌的定义越来越复杂,逐渐成为一种神秘的知识。例如,特劳…...
【Maven】-- 打包添加时间戳的两种方法
一、需求 在执行 mvn clean package -Dmaven.test.skiptrue 后,生成的 jar 包带有自定义系统时间。 二、实现 方法一:使用自带属性(不推荐) 使用系统时间戳,但有一个问题,就是默认使用 UTC0 的时区。举例…...
图片分类: 多类别
最近需要训练一个有200多类的图片分类网络,搜了一遍,发现居然没有很合适用的开源项目,于是自己简单撸了一个轮子,项目地址: https://github.com/xuduo35/imgcls_pytorch。支持如下backbone: alexnetresnet18,resnet34,resnet50,r…...
python 抓包tcp数据拷贝转发
在Python中,你可以使用scapy库进行抓包,使用shutil或io库进行数据的拷贝,以及使用socket库进行数据转发。下面是一个简单的示例,展示了如何进行这些操作: 首先,你需要安装必要的库。你可以使用pip来安装它…...
ubuntu 各版本图形界面和命令行切换快捷键介绍
文章目录 前言一、ubuntu 图形界面和命令行模式切换的快捷键1. ubuntu 16.042. ubuntu 18.043. ubuntu 20.044. ubuntu 22.04 总结 前言 本文主要介绍如何使用快捷键进行ubuntu 的图形界面和命令行模式切换,涉及如下 几个ubuntu 版本 ubuntu16.04 ubuntu18.04 ubun…...
基于SpringBoot Vue博物馆管理系统
大家好✌!我是Dwzun。很高兴你能来阅读我,我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结,还为大家分享优质的实战项目,本人在Java项目开发领域有多年的经验,陆续会更新更多优质的Java实战项目&#x…...
关于预检请求
基本概述 预检请求(Preflight Request)是一种由浏览器自动发起的请求,用于检查实际请求是否安全可行。这种请求通常在跨域请求(CORS)中出现,并且只在某些特定条件下触发。以下是触发预检请求的具体条件&am…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...
