辅助工具

什么是固定装置?

固定数据 是包含数据库序列化内容的文件集合。每个固定数据都有一个独有的名称,组成固定数据的文件可以分布在多个应用程序的多个目录中。

如何生成一个固定装置?

固定装置可以通过 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 调用中安装的任何数据都将从数据库中删除。

使用 MyISAM 的 MySQL 与固定数据

MySQL 的 MyISAM 存储引擎不支持事务或约束,所以如果你使用 MyISAM,你不会得到固定数据的数据验证,如果发现多个事务文件,也不会有回滚。

特定数据库的固定数据

如果你在一个多数据库配置中,你可能会有想加载到一个数据库,但不加载到另一个数据库的固定数据。在这种情况下,你可以在固定数据的名称中添加一个数据库标识符。

例如,如果你的 DATABASES 设置中定义了一个名为 users 的数据库,那么将固定装置命名为 mydata.users.jsonmydata.users.json.gz,那么这个固定装置只会在你指定要加载数据到 users 数据库时才会被加载。

Back to Top