網站首頁 編程語言 正文
一、前言
當我們在django中添加或修改了數據庫model后,一般需要執行makemigrations、migrate把我們的model類生成相應的數據庫表,或修改對應的表結構。這是非常方便的。
但我們在實際使用中執行這兩個命令經常會出現意向不到的報錯。下面為你詳細講解這兩個命令,讓你更從容的使用他們!
二、migrate和makemigrations詳解和實操
1. makemigrations
makemigrations會把我們寫的model生成數據庫遷移文件
比如我們建立一個一個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'
然后執行命令python manage.py makemigrations
會生成遷移文件(如果沒有生成遷移文件,記得添加【apps.py】文件并配置,再將其app名稱加入INSTALLED_APPS中)
如果我們有多個apps的文件可以指定app名稱進行遷移文件的生成,命令
python manage.py makemigrations [app_label]
一般我們使用這個命令就夠了!
當然還有其他命令給我們使用比如執行
python manage.py makemigrations --dry-run --verbosity 3
生成遷移文件的代碼
可以使用 python manage.py makemigrations --no-header
生成不帶django版本和遷移時間注釋的遷移文件
我們可以在對應的model代碼中加入配置項managed=False
來忽略遷移 這個時候再執行makemigrations
的時候則不會對該model進行遷移代碼的生成!
還有一些其他命令,但都不常用,可以閱讀官方文檔了解
2. 在協同開發的情況下,有沖突的遷移文件時如何解決?
在類似于使用git做協同開發時,我們應該有一個規范就是團隊中的每一個人都應該避免修改同一個model文件。但不可能保證每次的提交都能避免 migrations 的沖突!
這個時候我們可以使用python manage.py makemigrations --merge
進行合并來自動修復沖突,但這只適用于簡單的model沖突合并。如果太復雜了建議閱讀django的【writing-migrations】部分進行手動修改遷移文件
3. migrate
將遷移文件集同步到數據庫中.
如果想指定某個app遷移的話可以使用
python3 manage.py migrate [app_label]
如果想指定某個migrations文件的話可以使用
python3 manage.py migrate [app_label] [migration_name]
例如:python manage.py migrate cases 0011_auto_20220726_1440
在我們使用django-admin startproject
創建一個項目時后,如果需要使用django 的用戶管理、數據庫遷移等功能時就還需要配置好數據庫連接,然后執行migrate
數據庫會生成這些表
在表【django_migrations】中會記錄每次的mirage記錄。
有個問題是,我們的項目并沒有遷移文件,那migrate是走哪拿到遷移文件進行遷移的呢?
我們可以在【C:\Users\電腦用戶名\AppData\Local\Programs\Python\Python39\Lib\site-packages\django\contrib\auth\migrations】下找到自帶的用戶模型遷移文件。
我們還可以加參數 --database DATABASE
來指定遷移的數據庫
也可以使用--plan
顯示將要執行的遷移計劃
4. 遷移報錯怎么辦?
有些時候,我們直接對數據庫表字段進行了修改操作,而沒有修改對應的model代碼時,再執行makemigrations
、migrate
會報錯!
類似如下操作:
1)我們直接在數據庫表中刪除key這個字段
2)然后在對應的model代碼中刪除 【key】這個字段
3)這個時候再執行makemigrations
、migrate
,會發現migrate
的時候報錯了
報錯的原因是我們先在數據庫中刪除了key
這個字段,然后去修改的model文件進行遷移文件的生成和遷移。當migrate
的時候會執行刪除key
這個操作,但我們的表里面已經沒有這個字段了,所以會報錯!
當遇到這種情況的時候,我們可以使用migrate --fake
來進行修復。
它會將將向目標的遷移操作標記為已應用,但不實際運行 SQL 來更改數據庫結構。
另外使用migrate --fake-initial
可以對具有由CreateModel(建表操作)的遷移操作時,如果數據庫表已經存在,則允許 Django 跳過應用程序的初始遷移 。此選項適用于首次針對預先存在使用遷移的數據庫運行遷移時使用。但是,此選項不會檢查匹配表名稱之外的匹配數據庫架構,因此只有在您確信現有架構與初始遷移中記錄的架構匹配時才可以安全使用!
還有的其他命令操作不常用,需要了解可以參考官方文檔
三、遷移生成的外鍵約束有必要嗎
如果有外鍵的情況下,通過migrate
會在數據庫中建立相應的外鍵約束。這是一個很不錯的功能。在學校老師教學時,也會要求我們建立外鍵約束。
但在實際應用中并不是一個好的選擇,而且在《阿里Java開發規范手冊》中也明確規定:【強制】不得使用外鍵與級聯,一切外鍵概念必須在應用層解決
為什么要做這樣的規定呢?我們可以舉一個例子來說明:
現在我們建立了兩個Model:【product和project】,【project】的porduct
字段,關聯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'
然后我們進行遷移修改數據庫表
可以看到【project】表有了一條外鍵約束的記錄
當我們對【project】表增加一條project_id
為 1 的記錄的時候,由于【product】表不存在相應的記錄會導致報錯:
可以看出,這個約束的存在,會保證表間數據的關系的完整性。更不容易出現臟數據。這是外鍵約束非常明顯的優點!
但也存在著不可忽略的缺點:
性能問題
我們剛建立了兩張表【project】和【product】,【project】表通過project_id
字段與【product】表做了外鍵約束。
這個時候,當我們每次往【project】表插入數據的時候,它會先去【product】中查詢是否有對應的關聯數據,如果通過程序來控制可以不進行這次查詢。但設立了外鍵約束,就一定會去進行該查詢。這實際是冗余的。當關聯的字段少的時候可能沒啥影響,但一但關聯字段多了后,這種影響就尤其明顯!
死鎖
在我們每次修改【project】數據時,都需要去【product】表檢查數據,需要獲取額外的鎖。如果在高并發大流量的事務場景下,外鍵約束更容易造成死鎖!
開發/測試效率的降低
在我們日常的測試過程中,經常會遇到發現了一個BUG想復現或者方便測試的情況,會直接改數據庫表的數據來達到方便測試的效果。
雖然這及不規范,但實際情況就是能夠提升我們很多效率。這是毋庸置疑的!可是,這樣的操作也會帶來一些問題,比如因為數據導致的BUG,但實際并不是程序的BUG,或者發現不了一些潛在的BUG。
所以我的建議是:如果是業務相對復雜的話,可以在測試環境使用外鍵約束,但上了生產環境需要去掉!如果業務相對簡單,那完全可以刪除外鍵約束!
在django中,即便你刪除了數據庫中的外鍵約束,只要你model代碼里的外鍵關系還在,則還是可以使用它的ORM進行外鍵操作的,沒有區別!
四、反向遷移-inspectdb
inspectdb
命令會檢查你的settings文件指向的數據庫,將其數據庫表生成對應的django模型代碼并打印出來
也可以inspectdb
指定的模型 inspectdb product
原文鏈接:https://juejin.cn/post/7142817550047379493
相關推薦
- 2022-03-03 CSS樣式修改不換行顯示省略號及多行顯示省略號
- 2022-08-10 C#實現同步模式下的端口映射程序_C#教程
- 2022-12-24 Docker網絡及容器通信原理詳解_docker
- 2023-07-14 431報錯和解決方法
- 2022-11-09 Python?Pandas讀寫txt和csv文件的方法詳解_python
- 2022-12-24 TS裝飾器bindThis優雅實現React類組件中this綁定_React
- 2022-11-30 Python?Django教程之實現天氣應用程序_python
- 2022-06-20 關于Golang獲取當前項目絕對路徑的問題_Golang
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支