Spec-Zone.ru › Django 6.0

Фреймворк системных проверок

Фреймворк системных проверок — это набор статических проверок для валидации проектов Django. Он выявляет распространённые проблемы и предлагает способы их устранения. Фреймворк расширяем, поэтому вы можете легко добавлять собственные проверки.

Проверки можно запускать явно с помощью команды check. Неявно проверки запускаются перед выполнением большинства команд, включая runserver и migrate. По соображениям производительности проверки не запускаются в составе стека WSGI, используемого при развертывании. Если вам нужно запускать системные проверки на сервере развертывания, выполните их явно с помощью команды check.

Серьёзные ошибки не позволят командам Django (например, runserver) запуститься. Незначительные проблемы выводятся в консоль. Если вы выяснили причину предупреждения и решили его игнорировать, можно скрыть отдельные предупреждения с помощью настройки SILENCED_SYSTEM_CHECKS в файле настроек проекта.

Полный список всех проверок, которые могут выполняться в 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; это список приложений, которые следует проверить. Если None, проверка должна выполняться для всех установленных в проекте приложений.

Проверка получит именованный аргумент databases. Это список псевдонимов баз данных, подключения к которым можно использовать для проверки конфигурации на уровне базы данных. Если databases равно None, проверка не должна использовать подключения к базам данных.

Аргумент **kwargs необходим для будущих расширений.

Сообщения

Функция должна возвращать список сообщений. Если проверка не обнаружила проблем, функция проверки должна возвращать пустой список.

Предупреждения и ошибки, выдаваемые методом проверки, должны быть экземплярами CheckMessage. Экземпляр CheckMessage содержит одно сообщение об ошибке или предупреждении. Он также предоставляет контекст и рекомендации, относящиеся к сообщению, а также уникальный идентификатор, используемый для фильтрации.

Эта концепция очень похожа на сообщения из фреймворка сообщений или фреймворка журналирования. Сообщения помечаются level, указывающим на их уровень важности.

Также существуют сокращённые варианты, упрощающие создание сообщений с распространёнными уровнями важности. При использовании этих классов аргумент level можно опустить, поскольку его значение определяется именем класса.

  • Debug
  • Info
  • Warning
  • Error
  • Critical

Регистрация проверок и присвоение им меток

Наконец, функцию проверки необходимо явно зарегистрировать в реестре системных проверок. Проверки следует регистрировать в файле, который загружается вместе с приложением; например, в методе AppConfig.ready().

register(*tags)(function)

Вы можете передать 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. Это поле добавляет аргументы min и max в конструктор 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.

Чтобы добавить проверку для класса модели, подход почти тот же: единственное отличие в том, что проверка является методом класса, а не методом экземпляра:

class MyModel(models.Model):
    @classmethod
    def check(cls, **kwargs):
        errors = super().check(**kwargs)
        # ... your own checks ...
        return errors
Изменено в Django 6.0:

В предыдущих версиях ограничения не реализовывали метод check().

Написание тестов

Объекты сообщений можно сравнивать. Это позволяет легко писать тесты:

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)

Написание интеграционных тестов

Поскольку некоторые проверки необходимо регистрировать при загрузке приложения, может быть полезно протестировать их интеграцию с фреймворком системных проверок. Это можно сделать с помощью функции call_command().

Например, этот тест демонстрирует, что настройка SITE_ID должна быть целым числом. Это встроенная проверка фреймворка сайтов:

from django.core.management import call_command
from django.core.management.base import SystemCheckError
from django.test import SimpleTestCase, modify_settings, override_settings


class SystemCheckIntegrationTest(SimpleTestCase):
    @override_settings(SITE_ID="non_integer")
    @modify_settings(INSTALLED_APPS={"prepend": "django.contrib.sites"})
    def test_non_integer_site_id(self):
        message = "(sites.E101) The SITE_ID setting must be an integer."
        with self.assertRaisesMessage(SystemCheckError, message):
            call_command("check")

Рассмотрим следующую проверку, которая выдаёт предупреждение при развертывании, если пользовательская настройка с именем ENABLE_ANALYTICS не установлена в значение True:

from django.conf import settings
from django.core.checks import Warning, register


@register("myapp", deploy=True)
def check_enable_analytics_is_true_on_deploy(app_configs, **kwargs):
    errors = []
    if getattr(settings, "ENABLE_ANALYTICS", None) is not True:
        errors.append(
            Warning(
                "The ENABLE_ANALYTICS setting should be set to True in deployment.",
                id="myapp.W001",
            )
        )
    return errors

Поскольку эта проверка не выдаст SystemCheckError, наличие предупреждения в выводе stderr можно проверить следующим образом:

from io import StringIO

from django.core.management import call_command
from django.test import SimpleTestCase, override_settings


class EnableAnalyticsDeploymentCheckTest(SimpleTestCase):
    @override_settings(ENABLE_ANALYTICS=None)
    def test_when_set_to_none(self):
        stderr = StringIO()
        call_command("check", "-t", "myapp", "--deploy", stderr=stderr)
        message = (
            "(myapp.W001) The ENABLE_ANALYTICS setting should be set "
            "to True in deployment."
        )
        self.assertIn(message, stderr.getvalue())

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/6.0/topics/checks/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API