系统检查框架

系统检查框架是为了验证Django项目的一系列静态检查。 它可以检测到一般的问题,并且提供如何修复的提示。 这个框架可以被扩展,所以你可以轻易地添加你自己的检查。

检查可以由check命令显式触发。 检查会在大多数命令之前隐式触发,包括runservermigrate 由于性能因素,检查不作为在部署中使用的WSGI栈的一部分运行。 如果你需要在你的部署服务器上运行系统检查,显式使用check来触发它们。

严重的错误会完全阻止Django命令(像runserver)的运行。 少数问题会通过控制台来报告。 如果你检查了警告的原因,并且愿意无视它,你可以使用你项目设置文件中的SILENCED_SYSTEM_CHECKS 设置,来隐藏特定的警告。

System check reference中列出了所有Django可执行的所有检查。

编写自己的支票

这个框架十分灵活,允许你编写函数,执行任何其他类型的所需检查。 下面是一个桩(stub)检查函数的例子:

from django.core.checks import Error, register

@register()
def example_check(app_configs, **kwargs):
    errors = []
    # ... your check logic here
    if check_failed:
        errors.append(
            Error(
                'an error',
                hint='A hint.',
                obj=checked_object,
                id='myapp.E001',
            )
        )
    return errors

检查函数必须接受app_configs参数;这个参数是应该检查的应用程序的列表。 如果是None,检查会运行在项目中所有安装的应用上。 **kwargs参数用于进一步的扩展。

消息¶ T0>

这个函数必须返回消息的列表。 如果检查的结果中没有发现问题,检查函数必须返回一个空列表。

由检查方法产生的警告和错误必须是CheckMessage的实例。 CheckMessage的实例封装了一个可报告的错误或者警告。 它同时也提供了可应用到消息的上下文或者提示,以及一个用于过滤的唯一的标识符。

它的概念非常类似于message framework或者 logging framework中的消息。 消息使用表明其严重性的level 来标记。

也有一些快捷方式,使得创建通用级别的消息变得简单。 使用这些类时,您可以省略level参数,因为它是由类名隐含的。

注册和标签检查

最后,你的检查函数必须使用系统检查登记处来显式注册。 检查应注册在加载应用程序时加载的文件中;例如,在AppConfig.ready()方法中。

注册 T0>( *标记)(功能 T1>)¶ T2>

你可以向 register传递任意数量的标签来标记你的检查。 标记检查很有用,因为它允许您只运行一组特定的检查。 例如,要注册兼容性检查,您将进行以下调用:

from django.core.checks import register, Tags

@register(Tags.compatibility)
def my_check(app_configs, **kwargs):
    # ... perform compatibility checks and collect errors
    return errors

你可以注册“部署的检查”,它们只和产品配置文件相关,像这样:

@register(Tags.security, deploy=True)
def my_check(app_configs, **kwargs):
    ...

只有使用check --deploy选项,这些检查才会运行。

你也可以通过向register传递一个可调用对象(通常是个函数)作为第一个函数,将 register作为函数使用,而不是一个装饰器。

下面的代码和上面等价:

def my_check(app_configs, **kwargs):
    ...
register(my_check, Tags.security, deploy=True)

字段,模型,管理器和数据库检查

在一些情况下,你并不需要注册检查函数 -- 你可以直接使用现有的注册。

字段,模型,模型管理器和数据库后端都会实现已经在check框架中注册的check()方法。 如果你想要添加额外的检查,你可以扩展基类中的实现,进行任何你需要的额外检查,并且将任何消息附加到基类生成的消息中。 强烈推荐你将每个检查分配到单独的方法中。

在Django更改1.10:

添加了数据库后端检查。

考虑一个例子,其中你要实现一个叫做RangedIntegerField的自定义字段。 这个字段向min的构造器中添加maxIntegerField 参数。 你可能想添加一个检查,来确保用户提供了小于等于最大值的最小值。 下面的代码段展示了如何实现这个检查:

from django.core import checks
from django.db import models

class RangedIntegerField(models.IntegerField):
    def __init__(self, min=None, max=None, **kwargs):
        super(RangedIntegerField, self).__init__(**kwargs)
        self.min = min
        self.max = max

    def check(self, **kwargs):
        # Call the superclass
        errors = super(RangedIntegerField, self).check(**kwargs)

        # Do some custom checks and add messages to `errors`:
        errors.extend(self._check_min_max_values(**kwargs))

        # Return all errors and warnings
        return errors

    def _check_min_max_values(self, **kwargs):
        if (self.min is not None and
                self.max is not None and
                self.min > self.max):
            return [
                checks.Error(
                    'min greater than max.',
                    hint='Decrease min or increase max.',
                    obj=self,
                    id='myapp.E001',
                )
            ]
        # When no error, return an empty list
        return []

如果你想要向模型管理器添加检查,应该在你的Manager的子类上执行同样的方法。

如果你想要向模型类添加检查,方法也大致相同:唯一的不同是检查是类方法,并不是实例方法:

class MyModel(models.Model):
    @classmethod
    def check(cls, **kwargs):
        errors = super(MyModel, cls).check(**kwargs)
        # ... your own checks ...
        return errors

写作测试

消息是可比较的。 你可以轻易地编写测试:

from django.core.checks import Error
errors = checked_object.check()
expected_errors = [
    Error(
        'an error',
        hint='A hint.',
        obj=checked_object,
        id='myapp.E001',
    )
]
self.assertEqual(errors, expected_errors)