Spec-Zone.ru › Django 5.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

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

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

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/5.0/topics/checks/

Spec-Zone.ru

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