固定裝置

什麼是固定裝置?

固定裝置是一組檔案,其中包含資料庫序列化的內容。每個固定裝置都有一個獨特的名稱,而且組成該固定裝置的檔案可以分佈在多個應用程式的多個目錄中。

如何產生固定裝置?

固定裝置可以透過 manage.py dumpdata 產生。也可以直接使用 序列化工具 或是手動撰寫來產生自訂的固定裝置。

如何使用固定裝置?

固定裝置可以用於預先填入資料庫,以用於 測試

class MyTestCase(TestCase):
    fixtures = ["fixture-label"]

或是使用 loaddata 指令來提供一些 初始資料

django-admin loaddata <fixture label>

Django 在哪裡尋找固定裝置?

Django 將在以下位置搜尋固定裝置

  1. 在每個已安裝應用程式的 fixtures 目錄中

  2. FIXTURE_DIRS 設定中列出的任何目錄中

  3. 在固定裝置命名的文字路徑中

Django 將載入在這些位置找到的任何和所有符合所提供固定裝置名稱的固定裝置。如果命名的固定裝置具有檔案副檔名,則只會載入該類型的固定裝置。例如

django-admin loaddata mydata.json

只會載入名為 mydata 的 JSON 固定裝置。固定裝置的副檔名必須對應於 序列化器 的已註冊名稱(例如,jsonxml)。

如果省略副檔名,Django 將會搜尋所有可用的固定裝置類型以尋找符合的固定裝置。例如

django-admin loaddata mydata

將會尋找任何類型名為 mydata 的固定裝置。如果固定裝置目錄包含 mydata.json,則該固定裝置將會作為 JSON 固定裝置載入。

所命名的固定裝置可以包含目錄元件。這些目錄將會被包含在搜尋路徑中。例如

django-admin loaddata foo/bar/mydata.json

將會在每個已安裝的應用程式中搜尋 <app_label>/fixtures/foo/bar/mydata.json,在 FIXTURE_DIRS 中的每個目錄搜尋 <dirname>/foo/bar/mydata.json,以及搜尋文字路徑 foo/bar/mydata.json

固定裝置載入順序

可以在同一個調用中指定多個固定裝置。例如

django-admin loaddata mammals birds insects

或在測試案例類別中

class AnimalTestCase(TestCase):
    fixtures = ["mammals", "birds", "insects"]

固定裝置載入的順序遵循它們被列出的順序,無論是使用管理命令時或是將它們列在測試案例類別中(如上所示)。

在這些範例中,所有來自所有應用程式的 mammals 名稱的固定裝置(按照應用程式在 INSTALLED_APPS 中定義的順序)將會先載入。隨後,所有 birds 固定裝置將會載入,接著是所有 insects 固定裝置。

請注意,如果資料庫後端支援資料列層級的約束,這些約束將會在交易結束時檢查。如果資料庫配置不支援延遲約束檢查,則跨固定裝置的任何關係都可能導致載入錯誤(請參閱 MySQL 文件以取得範例)。

固定裝置如何儲存到資料庫?

當處理固定裝置檔案時,資料將會按原樣儲存到資料庫中。模型定義的 save() 方法不會被呼叫,並且任何 pre_savepost_save 信號將會以 raw=True 呼叫,因為實例只包含模型本機的屬性。例如,您可能想要停用在固定裝置載入期間會存取不存在的相關欄位的處理常式,否則會引發例外狀況。

from django.db.models.signals import post_save
from .models import MyModel


def my_handler(**kwargs):
    # disable the handler during fixture loading
    if kwargs["raw"]:
        return
    ...


post_save.connect(my_handler, sender=MyModel)

您也可以撰寫一個裝飾器來封裝此邏輯

from functools import wraps


def disable_for_loaddata(signal_handler):
    """
    Decorator that turns off signal handlers when loading fixture data.
    """

    @wraps(signal_handler)
    def wrapper(*args, **kwargs):
        if kwargs["raw"]:
            return
        signal_handler(*args, **kwargs)

    return wrapper


@disable_for_loaddata
def my_handler(**kwargs): ...

請注意,此邏輯將會停用在反序列化固定裝置時的信號,而不僅僅是在 loaddata 期間。

壓縮的固定裝置

固定裝置可以壓縮成 zipgzbz2lzmaxz 格式。例如

django-admin loaddata mydata.json

將會尋找 mydata.jsonmydata.json.zipmydata.json.gzmydata.json.bz2mydata.json.lzmamydata.json.xz 中的任何一個。使用壓縮檔中包含的第一個檔案。

請注意,如果發現兩個名稱相同但固定裝置類型不同的固定裝置(例如,如果在同一個固定裝置目錄中發現 mydata.jsonmydata.xml.gz),則會中止固定裝置的安裝,並且在呼叫 loaddata 時安裝的任何資料都將會從資料庫中移除。

MySQL 與 MyISAM 和固定裝置

MySQL 的 MyISAM 儲存引擎不支援交易或約束,因此如果您使用 MyISAM,您將不會獲得固定裝置資料的驗證,或是在找到多個交易檔案時進行回滾。

資料庫特定的固定裝置

如果您處於多資料庫設定中,您可能會有想要載入到一個資料庫但不載入到另一個資料庫的固定裝置資料。在這種情況下,您可以將資料庫識別碼加入到固定裝置的名稱中。

例如,如果您的 DATABASES 設定定義了一個 users 資料庫,請將固定裝置命名為 mydata.users.jsonmydata.users.json.gz,並且只有在您指定要將資料載入到 users 資料庫時才會載入固定裝置。

回到頂部