Django笔记二十之手动编写migration文件
本文首发于公众号:Hunter后端
原文链接:Django笔记二十之手动编写migration文件
前面介绍过,migration 文件主要记录的是 Django 系统 model 的变化,然后通过 migrate 命令将变化适配到数据库中。
比如在某个 application 下新增了某张表,或者对某张表更改了字段,可以生成 migration 文件,然后通过 migrate 更改到数据库。
除了系统能够自动生成的,我们还可以手动创建 migration 文件来操作数据库,这个用途主要是用于比如,创建表后,需要写入一些初始化的数据的情况。
- 基础命令
- migration文件介绍
- 自定义migration文件
- RunSQL()
- RunPython()
1、基础命令
关于 migration 的命令有如下几条:
- makemigrations
- migrate
- sqlmigrate
- showmigrations
其中 前面三条命令在第二篇笔记中已经介绍过使用方法,这里介绍一下 showmigrations。
这个作用主要是查看某个 application 下的migration 文件是否已经被更改到数据库中,可以在 Django 系统的根目录用下面的命令测试:
python3 manage.py showmigrations blog
可以看到下面的输出:
blog
[X] 0001_initial
[X] 0002_auto_20220118_0926
[X] 0003_auto_20220121_1016
其中,前面的 [X] 表示已经被更改到数据库中,如果我们再对 blog 的 model 进行任意修改,然后执行 makemigrations 的操作,再次执行 showmigrations 的操作,可以看到下面的输出:
blog
[X] 0001_initial
[X] 0002_auto_20220118_0926
[X] 0003_auto_20220121_1016
[ ] 0004_alter_book_price
可以看到最下面的一条记录 [] 中是没有 X 的,表示这条 migration 文件没有被执行 migrate。
2、migration文件介绍
每一次通过 makemigrations 生成的 migration 文件都存在系统中,一个最基础的 migration 文件像下面这样:
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [('blog', '0001_initial')]
operations = [
migrations.DeleteModel('Tribble'),
migrations.AddField('Author', 'rating', models.IntegerField(default=0)),
]
一个 Migration 的类下,有两个参数,一个是 dependencies,一个是 operations
dependencies 作用是定位上一个执行的 migration 文件的地方,因为每一次 migrate 的执行都是按照顺序的
且他的参数是一个列表,列表的元素是一个元组,里面有两个参数,一个是 application 的名称,一个是上一次运行的 migration 文件,他是可以指定到多个 application 的,意义为在某两个 application 的 migration 文件之后再执行
operations 的作用是 migration 里需要执行的操作,可以是字段的增加、删除、修改、也可以是表的创建和删除
一个 migration 在执行 migrate 前,我们可以手动对其修改,甚至可以完全自己来定义
3、自定义migration文件
前面介绍了 migration 文件的基本结构,其中有一些关于字段和 model 的操作方法,这些操作都可以通过 makemigration 的方式自动生成。
我们自定义的 migration 文件,与上面的保持一致即可,自定义的 migration 文件需要修改的地方是 operations 里的元素。
假设我们有这样一个需求,创建一张基础映射表后,里面是系统运行所必需的数据,需要在创建表后立即写入,那么就用到了我们这个自定义的 migration 文件。
除了对表字段或者表的修改,还有两种方法实现数据的写入,
一种是使用 SQL 语句插入,用到的migration的函数是 RunSQL()
一种是使用 Django 的 ORM 语句,写 python 的函数来插入,函数是 RunPython
假设创建 Blog 表的migration file 是 0001_create_blog.py
现在需要对其插入两条数据,name 和 tagline 分别是 ('name_1', 'tagline_1') 和 ('name_2', 'tagline_2')
下面用 RunSQL() 和 RunPython() 两种方式来分别介绍。
4、RunSQL()
RunSQL() 函数接受一个字符串,或者一个数组作为参数,参数的内容都是 SQL 语句,这也是为什么函数名为 RunSQL()。
字符串的形式为完整的 SQL 语句,比如我们需要插入这两条数据,则是:
migrations.RunSQL(
"INSERT INTO blog_blog (name, tagline) values('name_x_4', 'tagline_1'), ('name_x_5', 'tagline_2');"
)
如果是作为数组传入,形式则是:
migrations.RunSQL(
sql=[
(
"INSERT INTO blog_blog (name, tagline) values(%s, %s), (%s, %s);",
['name_x_6', 'tagline_1', 'name_x_7', 'tagline_2']
)
]
)
在数组的传入形式中,我们将需要插入的数据都放到一个数组中传入
reverse_sql
RunSQL() 函数除了 sql 参数,还有一个 reverse_sql 参数,用途是 sql 参数执行的 SQL 语句没有执行成功的情况下的一种操作,一般是用于防止数据污染。
假设说我们的 sql 为插入数据,但是因为某种原因,这条语句没有正确插入,报错了,那么系统就会执行 reverse_sql 中的语句,作为一个可逆的操作。
以下是官方的一个使用示例:
migrations.RunSQL(
sql=[("INSERT INTO musician (name) VALUES (%s);", ['Reinhardt'])],
reverse_sql=[("DELETE FROM musician where name=%s;", ['Reinhardt'])],
)
5、RunPython()
RunSQL() 函数操作的是 SQL 语句,RunPython() 参数则是 Python 函数,可以将我们需要写入的数据都写到函数的步骤里,然后在 RunPython() 中调用
以下是使用示例:
def insert_blog_data(apps, schema_editor):
Blog = apps.get_model("blog", "Blog")
db_alias = schema_editor.connection.alias
Blog.objects.using(db_alias).create(name="name_3", tagline="tagline_3")
Blog.objects.using(db_alias).create(name="name_4", tagline="tagline_4")
class Migration(migrations.Migration):
dependencies = [
("blog", "0001_initial"),
]
operations = [
migrations.RunPython(insert_blog_data)
]
其中,insert_blog_data 是需要执行的函数,在这个函数里,有两个默认参数,apps 和 schema_editor
apps 可以用来获取我们需要的 model,根据函数 apps.get_model(),
这个函数传入两个参数,一个是 application,我们这里是 blog,
一个 model 的名称,我们这里是 Blog
而 schema_editor 则是可以用于获取数据库的 alias
然后,数据的插入的方式就和普通的 model 的操作方法一致了。
RunPython() 函数和 RunSQL 一样,也可以输入两个参数,第二个参数作用也是用于操作失败的回退操作:
migrations.RunPython(insert_blog_data, reverse_insert)
以上就是介绍 migration 的全部内容了,下一篇笔记将介绍如何在 Django 中使用原生的 SQL 来查询数据。
如果想获取更多后端相关文章,可扫码关注阅读:

Django笔记二十之手动编写migration文件的更多相关文章
- python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法
python3.4学习笔记(二十四) Python pycharm window安装redis MySQL-python相关方法window安装redis,下载Redis的压缩包https://git ...
- python3.4学习笔记(二十六) Python 输出json到文件,让json.dumps输出中文 实例代码
python3.4学习笔记(二十六) Python 输出json到文件,让json.dumps输出中文 实例代码 python的json.dumps方法默认会输出成这种格式"\u535a\u ...
- python3.4学习笔记(二十五) Python 调用mysql redis实例代码
python3.4学习笔记(二十五) Python 调用mysql redis实例代码 #coding: utf-8 __author__ = 'zdz8207' #python2.7 import ...
- python3.4学习笔记(二十二) python 在字符串里面插入指定分割符,将list中的字符转为数字
python3.4学习笔记(二十二) python 在字符串里面插入指定分割符,将list中的字符转为数字在字符串里面插入指定分割符的方法,先把字符串变成list然后用join方法变成字符串str=' ...
- python3.4学习笔记(二十) python strip()函数 去空格\n\r\t函数的用法
python3.4学习笔记(二十) python strip()函数 去空格\n\r\t函数的用法 在Python中字符串处理函数里有三个去空格(包括'\n', '\r', '\t', ' ')的函数 ...
- django笔记二之数据库
django笔记二之数据库 [同步数据库之前的操作] yum install MySQL-python.x86_64 -y 2)开启数据库服务并创建表 创建数据库设置 为utf8: create da ...
- (C/C++学习笔记) 二十四. 知识补充
二十四. 知识补充 ● 子类调用父类构造函数 ※ 为什么子类要调用父类的构造函数? 因为子类继承父类,会继承到父类中的数据,所以子类在进行对象初始化时,先调用父类的构造函数,这就是子类的实例化过程. ...
- (C/C++学习笔记) 二十二. 标准模板库
二十二. 标准模板库 ● STL基本介绍 标准模板库(STL, standard template library): C++提供的大量的函数模板(通用算法)和类模板. ※ 为什么我们一般不需要自己写 ...
- (C/C++学习笔记) 二十. 文件和流
二十. 文件和流 ● 文件的概念 文件(file) 一. C/C++语言将文件作为字节序列(sequence of characters)来对待,但从编码角度,或说从对字节信息的解释来看,文件分为:文 ...
- python 学习笔记二十 django项目bbs论坛
项目:开发一个简单的BBS论坛 需求: 整体参考“抽屉新热榜” + “虎嗅网” 实现不同论坛版块 帖子列表展示 帖子评论数.点赞数展示 在线用户展示 允许登录用户发贴.评论.点赞 允许上传文件 帖子可 ...
随机推荐
- 关于Python文件读取时,默认把\r\n换成\n
Python在非二进制形式读取文件时,自动把\r\n换成\n.(window下换行是\r\n) 建立一个test1.txt文件, aaaa bbbb 1.在utf8方式下读取 读取四个字符 1 f=o ...
- List,Set,Map存取元素各有什么特点 hashMap、hashTable的区别 Arraylist和linkedList的区别
1.List,Set,Map存取元素各有什么特点? 1.存放 (1)List存放元素是有序,可重复 (2)Set存放元素无序,不可重复 (3)Map元素键值对形式存放,键无序不可重复,值可重复 2.取 ...
- Blog作业03
目录 前言 设计与分析 踩坑心得 改进建议 总结 前言 这三次作业的题目只有2道题,但是在题量减小的同时,这三次作业集的难度也相应的上去了,题目的质量很好,运用很广泛,也考验了很多的知识点.这三次的作 ...
- Eclipse's Import error and remove
1.导入项目之前,请确认工作空间编码已设置为utf-8:window->Preferences->General->Wrokspace->Text file encoding- ...
- 5G如何加速无人快递?5G智能网关新应用
网上购物已经是现代生活的主流消费方式之一,伴随网购的繁荣,物流快递行业也进入到一个最火热的时期.而在这之中,有限的快递配送能力和日益增长的配送需求的矛盾持续凸显,因此无人快递车一类的创新应用也应运而生 ...
- SpringSecurity登录验证,多个用户表
在开始之前我想感叹一句,技术久了不回头看看真的会忘记的,这次公司让我重新开发一个程序,项目架构为单体多模块开发,其中有个需求就是需要不同用户表进行登录,且不同表的用户名.手机号都可以重复. 这样的需求 ...
- redhat安装mysql8.0
redhat 安装mysql 8.0 * 看mysql官方文档 * 安装epel源 * 安装mysql源 参考文章 redhat7通过yum安装mysql5.7.17教程:https://www.jb ...
- .net 学习必须学的书籍,新手必备,老手升级必须品!!!
最近看到一篇文章 是关于学习.net的数据 给大家看看. <<第一篇:>> 人身为一个典型的技术宅,平时看了一些技术书籍.算不上是"博览群书",但也涉猎不少 ...
- group by和union,Laravel分页
$res3 = DB::table('users') ->join('user_folow_boutiques', 'user_folow_boutiques.user_id', '=', 'u ...
- 关于 Android sdk manager 的安装问题
最近刚刚接触小程序测试,故此需要搭建环境 我用的是python3.6+appium1.8.2+Android sdk manager 关于应用程序,大家有需要的话,可以找我要. 1.关于安装Andro ...