- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
本文首发于公众号:Hunter后端 原文链接: Django笔记二十之手动编写migration文件 。
前面介绍过,migration 文件主要记录的是 Django 系统 model 的变化,然后通过 migrate 命令将变化适配到数据库中.
比如在某个 application 下新增了某张表,或者对某张表更改了字段,可以生成 migration 文件,然后通过 migrate 更改到数据库.
除了系统能够自动生成的,我们还可以手动创建 migration 文件来操作数据库,这个用途主要是用于比如,创建表后,需要写入一些初始化的数据的情况.
关于 migration 的命令有如下几条:
其中 前面三条命令在第二篇笔记中已经介绍过使用方法,这里介绍一下 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.
每一次通过 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 前,我们可以手动对其修改,甚至可以完全自己来定义 。
前面介绍了 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() 两种方式来分别介绍.
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'])],
)
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文件的文章就讲到这里了,如果你想了解更多关于Django笔记二十之手动编写migration文件的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我只想从客户端向服务器发送数组 adc_array=[w, x, y, z]。下面是客户端代码,而我的服务器是在只接受 json 的 python 中。编译代码时我没有收到任何错误,但收到 2 条警告
我是 lua 和 Node js 的新手,我正在尝试将我正在开发的移动应用程序连接到服务器。问题是它连接到服务器,但我尝试传递的数据丢失或无法到达服务器。对我正在做的事情有什么问题有什么想法吗? th
我在这个页面上工作 http://www.haskell.org/haskellwiki/99_questions/Solutions/4 我理解每个函数的含义,看到一个函数可以像这样以多种方式定义,
我目前正在尝试将数据写入 excel 以生成报告。我可以将数据写入 csv 文件,但它不会按照我想要的顺序出现在 excel 中。我需要数据在每列的最佳和最差适应性下打印,而不是全部打印在平均值下。这
所以,我正在做一个项目,现在我有一个问题,所以我想得到你的帮助:) 首先,我已经知道如何编写和读取 .txt 文件,但我想要的不仅仅是 x.hasNext()。 我想知道如何像 .ini 那样编写、读
我正在尝试编写一个函数,该函数将返回作为输入给出的任何数字的阶乘。现在,我的代码绝对是一团糟。请帮忙。 function factorialize(num) { for (var i=num, i
这个问题已经有答案了: Check variable equality against a list of values (16 个回答) 已关闭 4 年前。 有没有一种简洁或更好的方法来编写这个条件
我对 VR 完全陌生,正在 AFrame 中为一个类(class)项目开发 VR 太空射击游戏,并且想知道 AFrame 中是否有 TDD 的任何文档/标准。有人能指出我正确的方向吗? 最佳答案 几乎
我正在尝试创建一个 for 循环,它将重现以下功能代码块,但以一种更具吸引力的方式。这是与 Soundcould 小部件 API 实现一起使用的 here on stackoverflow $(doc
我有一个非常令人困惑的问题。我正在尝试更改属性文件中的属性,但它只是没有更改... 这是代码: package config; import java.io.FileNotFoundException
我对 VR 完全陌生,正在 AFrame 中为一个类(class)项目开发 VR 太空射击游戏,并且想知道 AFrame 中是否有 TDD 的任何文档/标准。有人能指出我正确的方向吗? 最佳答案 几乎
我正在开发一个用户模式(Ring3)代码级调试器。它还应支持.NET可执行文件的本机(x86)调试。基本上,我需要执行以下操作: 1).NET在隐身模式下加载某些模块,而没有LOAD_DLL_DEBU
我有一个列表,我知道有些项目是不必要打印的,我正在尝试通过 if 语句来做到这一点...但是它变得非常复杂,所以有没有什么方法可以在 if 语句中包含多个索引而无需打印重写整个声明。 看起来像这样的东
我很好奇以不同方式编写 if 语句是否会影响程序的速度和效率。所以,例如写一个这样的: bool isActive = true; bool isResponding = false; if (isA
我在搜索网站的源代码时找到了一种以另一种方式(我认为)编写 if 语句的方法。 代替: if(a)b; 或: a?b:''; 我读了: !a||b; 第三种方式和前两种方式一样吗?如果是,为什么我们要
我的数据采用以下格式(HashMap的列表) {TeamName=India, Name=Sachin, Score=170} {TeamName=India, Name=Sehwag, Score=
我目前正在完成 More JOIN operations sqlzoo 的教程,遇到了下面的代码作为#12 的答案: SELECT yr,COUNT(title) FROM movie JOIN ca
我正试图找到一种更好的方法来编写这段代码: def down_up(array, player) 7.downto(3).each do |row| 8.times do |col
出于某种原因,我的缓冲区中充满了乱码,我不确定为什么。我什至用十六进制编辑器检查了我的文件,以验证我的字符是否以 2 字节的 unicode 格式保存。我不确定出了什么问题。 [打开文件] fseek
阅读编码恐怖片时,我刚刚又遇到了 FizzBuzz。 原帖在这里:Coding Horror: Why Can't Programmers.. Program? 对于那些不知道的人:FizzBu
我是一名优秀的程序员,十分优秀!