辅助工具

What is a fixture?

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

How to produce a fixture?

Fixtures can be generated by manage.py dumpdata. It's also possible to generate custom fixtures by directly using serialization documentation tools or even by handwriting them.

What to use a fixture for?

Fixtures can be used to pre-populate database with data for tests or to provide some initial data.

Were Django looks for fixtures?

Django 会在三个位置搜索固定数据:

  1. 在每个安装的应用程序的 fixtures 目录中
  2. FIXTURE_DIRS 配置中命名的任何目录中
  3. 在由固定数据命名的文字路径中

Django 将加载它在这些位置找到的与所提供的固定数据名称相匹配的任何和所有固定数据。

If the named fixture has a file extension, only fixtures of that type will be loaded. For example:

django-admin loaddata mydata.json

将只加载名为 mydata 的 JSON 固定数据。固定数据扩展必须与 序列化器 的注册名称相对应(例如,jsonxml)。

If you omit the extensions, Django will search all available fixture types for a matching fixture. For example:

django-admin loaddata mydata

将寻找任何固定数据类型的名为 mydata 的固定数据。如果一个固定数据目录包含 mydata.json,该固定数据将作为 JSON 固定数据加载。

The fixtures that are named can include directory components. These directories will be included in the search path. For example:

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

How fixtures are saved to the database?

当固定数据文件被处理后,数据会被原样保存到数据库中。模型定义的 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 期间。

请注意,处理夹固定数据文件的顺序是未定义的。然而,所有的固定数据的数据都是作为一个事务安装的,因此一个固定数据中的数据可以引用另一个固定数据中的数据。如果数据库后端支持行级约束,这些约束将在事务结束时被检查。

压缩的固定数据

Fixtures may be compressed in zip, gz, bz2, lzma, or xz format. For example:

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,你不会得到固定数据的数据验证,如果发现多个事务文件,也不会有回滚。

特定数据库的固定数据

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

For example, if your DATABASES setting has a users database defined, name the fixture mydata.users.json or mydata.users.json.gz and the fixture will only be loaded when you specify you want to load data into the users database.