Django中Migrate和Makemigrations實(shí)操詳解
一、前言
當(dāng)我們?cè)赿jango中添加或修改了數(shù)據(jù)庫(kù)model后,一般需要執(zhí)行makemigrations、migrate把我們的model類(lèi)生成相應(yīng)的數(shù)據(jù)庫(kù)表,或修改對(duì)應(yīng)的表結(jié)構(gòu)。這是非常方便的。
但我們?cè)趯?shí)際使用中執(zhí)行這兩個(gè)命令經(jīng)常會(huì)出現(xiàn)意向不到的報(bào)錯(cuò)。下面為你詳細(xì)講解這兩個(gè)命令,讓你更從容的使用他們!
二、migrate和makemigrations詳解和實(shí)操
1. makemigrations
makemigrations會(huì)把我們寫(xiě)的model生成數(shù)據(jù)庫(kù)遷移文件
比如我們建立一個(gè)一個(gè)Product的模型
class Product(models.Model): id = models.AutoField(primary_key=True) key = models.CharField(max_length=255) created = models.DateTimeField() suite_id = models.IntegerField(blank=True, null=True) report_version_id = models.IntegerField(null=True) class Meta: db_table = 'client'
然后執(zhí)行命令python manage.py makemigrations
會(huì)生成遷移文件(如果沒(méi)有生成遷移文件,記得添加【apps.py】文件并配置,再將其app名稱(chēng)加入INSTALLED_APPS中)
如果我們有多個(gè)apps的文件可以指定app名稱(chēng)進(jìn)行遷移文件的生成,命令
python manage.py makemigrations [app_label]
一般我們使用這個(gè)命令就夠了!
當(dāng)然還有其他命令給我們使用比如執(zhí)行
python manage.py makemigrations --dry-run --verbosity 3
生成遷移文件的代碼
可以使用 python manage.py makemigrations --no-header
生成不帶django版本和遷移時(shí)間注釋的遷移文件
我們可以在對(duì)應(yīng)的model代碼中加入配置項(xiàng)managed=False
來(lái)忽略遷移 這個(gè)時(shí)候再執(zhí)行makemigrations
的時(shí)候則不會(huì)對(duì)該model進(jìn)行遷移代碼的生成!
還有一些其他命令,但都不常用,可以閱讀官方文檔了解
2. 在協(xié)同開(kāi)發(fā)的情況下,有沖突的遷移文件時(shí)如何解決?
在類(lèi)似于使用git做協(xié)同開(kāi)發(fā)時(shí),我們應(yīng)該有一個(gè)規(guī)范就是團(tuán)隊(duì)中的每一個(gè)人都應(yīng)該避免修改同一個(gè)model文件。但不可能保證每次的提交都能避免 migrations 的沖突!
這個(gè)時(shí)候我們可以使用python manage.py makemigrations --merge
進(jìn)行合并來(lái)自動(dòng)修復(fù)沖突,但這只適用于簡(jiǎn)單的model沖突合并。如果太復(fù)雜了建議閱讀django的【writing-migrations】部分進(jìn)行手動(dòng)修改遷移文件
3. migrate
將遷移文件集同步到數(shù)據(jù)庫(kù)中.
如果想指定某個(gè)app遷移的話可以使用
python3 manage.py migrate [app_label]
如果想指定某個(gè)migrations文件的話可以使用
python3 manage.py migrate [app_label] [migration_name]
例如:python manage.py migrate cases 0011_auto_20220726_1440
在我們使用django-admin startproject
創(chuàng)建一個(gè)項(xiàng)目時(shí)后,如果需要使用django 的用戶(hù)管理、數(shù)據(jù)庫(kù)遷移等功能時(shí)就還需要配置好數(shù)據(jù)庫(kù)連接,然后執(zhí)行migrate
數(shù)據(jù)庫(kù)會(huì)生成這些表
在表【django_migrations】中會(huì)記錄每次的mirage記錄。
有個(gè)問(wèn)題是,我們的項(xiàng)目并沒(méi)有遷移文件,那migrate是走哪拿到遷移文件進(jìn)行遷移的呢?
我們可以在【C:\Users\電腦用戶(hù)名\AppData\Local\Programs\Python\Python39\Lib\site-packages\django\contrib\auth\migrations】下找到自帶的用戶(hù)模型遷移文件。
我們還可以加參數(shù) --database DATABASE
來(lái)指定遷移的數(shù)據(jù)庫(kù)
也可以使用--plan
顯示將要執(zhí)行的遷移計(jì)劃
4. 遷移報(bào)錯(cuò)怎么辦?
有些時(shí)候,我們直接對(duì)數(shù)據(jù)庫(kù)表字段進(jìn)行了修改操作,而沒(méi)有修改對(duì)應(yīng)的model代碼時(shí),再執(zhí)行makemigrations
、migrate
會(huì)報(bào)錯(cuò)!
類(lèi)似如下操作:
1)我們直接在數(shù)據(jù)庫(kù)表中刪除key這個(gè)字段
2)然后在對(duì)應(yīng)的model代碼中刪除 【key】這個(gè)字段
3)這個(gè)時(shí)候再執(zhí)行makemigrations
、migrate
,會(huì)發(fā)現(xiàn)migrate
的時(shí)候報(bào)錯(cuò)了
報(bào)錯(cuò)的原因是我們先在數(shù)據(jù)庫(kù)中刪除了key
這個(gè)字段,然后去修改的model文件進(jìn)行遷移文件的生成和遷移。當(dāng)migrate
的時(shí)候會(huì)執(zhí)行刪除key
這個(gè)操作,但我們的表里面已經(jīng)沒(méi)有這個(gè)字段了,所以會(huì)報(bào)錯(cuò)!
當(dāng)遇到這種情況的時(shí)候,我們可以使用migrate --fake
來(lái)進(jìn)行修復(fù)。
它會(huì)將將向目標(biāo)的遷移操作標(biāo)記為已應(yīng)用,但不實(shí)際運(yùn)行 SQL 來(lái)更改數(shù)據(jù)庫(kù)結(jié)構(gòu)。
另外使用migrate --fake-initial
可以對(duì)具有由CreateModel(建表操作)的遷移操作時(shí),如果數(shù)據(jù)庫(kù)表已經(jīng)存在,則允許 Django 跳過(guò)應(yīng)用程序的初始遷移 。此選項(xiàng)適用于首次針對(duì)預(yù)先存在使用遷移的數(shù)據(jù)庫(kù)運(yùn)行遷移時(shí)使用。但是,此選項(xiàng)不會(huì)檢查匹配表名稱(chēng)之外的匹配數(shù)據(jù)庫(kù)架構(gòu),因此只有在您確信現(xiàn)有架構(gòu)與初始遷移中記錄的架構(gòu)匹配時(shí)才可以安全使用!
還有的其他命令操作不常用,需要了解可以參考官方文檔
三、遷移生成的外鍵約束有必要嗎
如果有外鍵的情況下,通過(guò)migrate
會(huì)在數(shù)據(jù)庫(kù)中建立相應(yīng)的外鍵約束。這是一個(gè)很不錯(cuò)的功能。在學(xué)校老師教學(xué)時(shí),也會(huì)要求我們建立外鍵約束。
但在實(shí)際應(yīng)用中并不是一個(gè)好的選擇,而且在《阿里Java開(kāi)發(fā)規(guī)范手冊(cè)》中也明確規(guī)定:【強(qiáng)制】不得使用外鍵與級(jí)聯(lián),一切外鍵概念必須在應(yīng)用層解決
為什么要做這樣的規(guī)定呢?我們可以舉一個(gè)例子來(lái)說(shuō)明:
現(xiàn)在我們建立了兩個(gè)Model:【product和project】,【project】的porduct
字段,關(guān)聯(lián)Product
class Product(models.Model): id = models.AutoField(primary_key=True) created = models.DateTimeField() product_name = models.CharField(max_length=100, null=True) class Meta: db_table = 'product' class Project(models.Model): id = models.AutoField(primary_key=True) product = models.ForeignKey(to=Product, on_delete=models.PROTECT) project_name = models.CharField(max_length=100, null=True) class Meta: db_table = 'project'
然后我們進(jìn)行遷移修改數(shù)據(jù)庫(kù)表
可以看到【project】表有了一條外鍵約束的記錄
當(dāng)我們對(duì)【project】表增加一條project_id
為 1 的記錄的時(shí)候,由于【product】表不存在相應(yīng)的記錄會(huì)導(dǎo)致報(bào)錯(cuò):
可以看出,這個(gè)約束的存在,會(huì)保證表間數(shù)據(jù)的關(guān)系的完整性。更不容易出現(xiàn)臟數(shù)據(jù)。這是外鍵約束非常明顯的優(yōu)點(diǎn)!
但也存在著不可忽略的缺點(diǎn):
性能問(wèn)題
我們剛建立了兩張表【project】和【product】,【project】表通過(guò)project_id
字段與【product】表做了外鍵約束。
這個(gè)時(shí)候,當(dāng)我們每次往【project】表插入數(shù)據(jù)的時(shí)候,它會(huì)先去【product】中查詢(xún)是否有對(duì)應(yīng)的關(guān)聯(lián)數(shù)據(jù),如果通過(guò)程序來(lái)控制可以不進(jìn)行這次查詢(xún)。但設(shè)立了外鍵約束,就一定會(huì)去進(jìn)行該查詢(xún)。這實(shí)際是冗余的。當(dāng)關(guān)聯(lián)的字段少的時(shí)候可能沒(méi)啥影響,但一但關(guān)聯(lián)字段多了后,這種影響就尤其明顯!
死鎖
在我們每次修改【project】數(shù)據(jù)時(shí),都需要去【product】表檢查數(shù)據(jù),需要獲取額外的鎖。如果在高并發(fā)大流量的事務(wù)場(chǎng)景下,外鍵約束更容易造成死鎖!
開(kāi)發(fā)/測(cè)試效率的降低
在我們?nèi)粘5臏y(cè)試過(guò)程中,經(jīng)常會(huì)遇到發(fā)現(xiàn)了一個(gè)BUG想復(fù)現(xiàn)或者方便測(cè)試的情況,會(huì)直接改數(shù)據(jù)庫(kù)表的數(shù)據(jù)來(lái)達(dá)到方便測(cè)試的效果。
雖然這及不規(guī)范,但實(shí)際情況就是能夠提升我們很多效率。這是毋庸置疑的!可是,這樣的操作也會(huì)帶來(lái)一些問(wèn)題,比如因?yàn)閿?shù)據(jù)導(dǎo)致的BUG,但實(shí)際并不是程序的BUG,或者發(fā)現(xiàn)不了一些潛在的BUG。
所以我的建議是:如果是業(yè)務(wù)相對(duì)復(fù)雜的話,可以在測(cè)試環(huán)境使用外鍵約束,但上了生產(chǎn)環(huán)境需要去掉!如果業(yè)務(wù)相對(duì)簡(jiǎn)單,那完全可以刪除外鍵約束!
在django中,即便你刪除了數(shù)據(jù)庫(kù)中的外鍵約束,只要你model代碼里的外鍵關(guān)系還在,則還是可以使用它的ORM進(jìn)行外鍵操作的,沒(méi)有區(qū)別!
四、反向遷移-inspectdb
inspectdb
命令會(huì)檢查你的settings文件指向的數(shù)據(jù)庫(kù),將其數(shù)據(jù)庫(kù)表生成對(duì)應(yīng)的django模型代碼并打印出來(lái)
也可以inspectdb
指定的模型 inspectdb product
以上就是Django中Migrate和Makemigrations實(shí)操詳解的詳細(xì)內(nèi)容,更多關(guān)于Django Migrate Makemigrations的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python實(shí)現(xiàn)語(yǔ)音合成功能詳解
這篇文章主要為大家介紹了一個(gè)通過(guò)Python制作的小工具,可以實(shí)現(xiàn)語(yǔ)音識(shí)別以及文字轉(zhuǎn)語(yǔ)音的功能,文中的實(shí)現(xiàn)步驟講解詳細(xì),感興趣的可以動(dòng)手試一試2022-01-01python爬取”頂點(diǎn)小說(shuō)網(wǎng)“《純陽(yáng)劍尊》的示例代碼
這篇文章主要介紹了python爬取”頂點(diǎn)小說(shuō)網(wǎng)“《純陽(yáng)劍尊》的示例代碼,幫助大家更好的利用python 爬蟲(chóng)爬取數(shù)據(jù),感興趣的朋友可以了解下2020-10-10Python實(shí)現(xiàn)極限車(chē)神游戲的示例代碼
今天小編要為大家介紹一款小編自己用Python代碼碼出來(lái)的賽車(chē)風(fēng)格的打字小游戲,不僅能游戲還能學(xué)到很多不同類(lèi)型的編程代碼關(guān)鍵字的語(yǔ)言,需要的可以參考一下2023-02-02Python找出列表中出現(xiàn)次數(shù)最多的元素三種方式
本文通過(guò)三種方式給大家介紹Python找出列表中出現(xiàn)次數(shù)最多的元素,每種方式通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下2020-02-02Python實(shí)現(xiàn)的排列組合、破解密碼算法示例
這篇文章主要介紹了Python實(shí)現(xiàn)的排列組合、破解密碼算法,結(jié)合實(shí)例形式分析了Python排列組合、密碼破解相關(guān)數(shù)學(xué)運(yùn)算操作技巧,需要的朋友可以參考下2019-04-04