辅助工具

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 tools or even by handwriting them.

How to use a fixture?

Fixtures can be used to pre-populate database with data for tests:

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

or to provide some initial data using the loaddata command:

django-admin loaddata <fixture label>

Where Django looks for fixtures?

Django will search in these locations for fixtures:

  1. 在每个安装的应用程序的 fixtures 目录中
  2. In any directory listed in the FIXTURE_DIRS setting
  3. 在由固定数据命名的文字路径中

Django will load any and all fixtures it finds in these locations that match the provided fixture names. 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

would search <app_label>/fixtures/foo/bar/mydata.json for each installed application, <dirname>/foo/bar/mydata.json for each directory in FIXTURE_DIRS, and the literal path foo/bar/mydata.json.

Fixtures loading order

Multiple fixtures can be specified in the same invocation. For example:

django-admin loaddata mammals birds insects

or in a test case class:

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

The order in which fixtures are loaded follows the order in which they are listed, whether it's when using the management command or when listing them in the test case class as shown above.

In these examples, all the fixtures named mammals from all applications (in the order in which applications are defined in INSTALLED_APPS) will be loaded first. Subsequently, all the birds fixtures will be loaded, followed by all the insects fixtures.

Be aware that if the database backend supports row-level constraints, these constraints will be checked at the end of the transaction. Any relationships across fixtures may result in a load error if the database configuration does not support deferred constraint checking (refer to the MySQL docs for an example).

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):
    ...

Just be aware that this logic will disable the signals whenever fixtures are deserialized, not just during 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。压缩档案中包含的第一个文件被使用。

Note that if two fixtures with the same name but different fixture type are discovered (for example, if mydata.json and mydata.xml.gz were found in the same fixture directory), fixture installation will be aborted, and any data installed in the call to loaddata will be removed from the database.

使用 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.