首頁 > 軟體

Django中Migrate和Makemigrations實操詳解

2022-09-14 22:03:05

一、前言

當我們在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電腦使用者名稱AppDataLocalProgramsPythonPython39Libsite-packagesdjangocontribauthmigrations】下找到自帶的使用者模型遷移檔案。

我們還可以加引數 --database DATABASE 來指定遷移的資料庫

也可以使用--plan 顯示將要執行的遷移計劃

4. 遷移報錯怎麼辦?

有些時候,我們直接對資料庫表欄位進行了修改操作,而沒有修改對應的model程式碼時,再執行makemigrationsmigrate會報錯!

類似如下操作:

1)我們直接在資料庫表中刪除key這個欄位

2)然後在對應的model程式碼中刪除 【key】這個欄位

3)這個時候再執行makemigrationsmigrate,會發現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

以上就是Django中Migrate和Makemigrations實操詳解的詳細內容,更多關於Django Migrate Makemigrations的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com