文章目錄一、前言一、方式1:spring 官方創建 springboot項目1、打開線上的 spring initializr2、選擇項目的語言、版本、依賴等3、 解壓源碼包,並使用IDEA打開4、測試介面二、方式2:社區idea安裝Spring插件1、添加插件三、方式3:(麻煩)手動maven 創 ...
本文首發於公眾號: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 來查詢數據。
如果想獲取更多後端相關文章,可掃碼關註閱讀: