系统检查框架

系统检查框架是一组验证Django项目的静态检查。 它检测到常见的问题,并提供了如何解决这些问题的提示。 该框架是可扩展的,所以你可以轻松地添加自己的检查。

检查可以通过check命令显式触发。 大多数命令(包括runservermigrate)都会隐式触发检查。 出于性能原因,检查不会作为部署中使用的WSGI堆栈的一部分运行。 如果您需要在部署服务器上运行系统检查,请使用check显式触发它们。

严重的错误会阻止Django命令(如runserver)运行。 小问题会报告给控制台。 如果您检查了警告的原因,并且很乐意忽略它,则可以在项目设置文件中使用SILENCED_SYSTEM_CHECKS设置来隐藏特定的警告。

可以在System check reference中找到可以由Django提出的所有检查的完整列表。

写你自己的支票

该框架是灵活的,并允许您编写执行任何其他类型的检查您可能需要的功能。 以下是一个示例存根检查功能:

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参数;这个参数是应该被检查的应用程序的列表。 如果没有,则必须在项目中的所有安装的应用程序上运行检查。 将来的扩展需要**kwargs参数。

消息¶ T0>

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

检查方法引发的警告和错误必须是CheckMessage的实例。 一个CheckMessage的实例封装了一个可报告的错误或警告。 它还提供适用于消息的上下文和提示以及用于过滤目的的唯一标识符。

该概念与来自message frameworklogging 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()方法。 如果你想添加额外的检查,你可以扩展在基类的实现,执行任何额外的检查你需要的,并追加到基类生成的消息。 建议您将每个支票委托给单独的方法。

考虑一个例子,你正在实现一个名为RangedIntegerField的自定义字段。 该字段将minmax参数添加到IntegerField的构造函数中。 您可能需要添加一个检查来确保用户提供的最小值小于或等于最大值。 以下代码片段显示了如何实现此检查:

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

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

    def check(self, **kwargs):
        # Call the superclass
        errors = super().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的子类中使用相同的方法。

If you want to add a check to a model class, the approach is almost the same: the only difference is that the check is a classmethod, not an instance method:

class MyModel(models.Model):
    @classmethod
    def check(cls, **kwargs):
        errors = super().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)