Система проверки системы
Система проверки системы — это набор статических проверок для валидации проектов 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 encapsulates a single reportable error or warning. Он также предоставляет контекст и подсказки, относящиеся к сообщению, а также уникальный идентификатор, используемый для целей фильтрации.
Концепция очень похожа на сообщения из системы сообщений или системы логирования. Сообщения помечены level, указывающим на степень важности сообщения.
Также есть сокращения, которые упрощают создание сообщений с общими уровнями. При использовании этих классов вы можете опустить аргумент level, поскольку он подразумевается именем класса.
Регистрация и маркировка проверок
Наконец, ваша функция проверки должна быть явно зарегистрирована в реестре проверок системы. Проверки должны быть зарегистрированы в файле, который загружается при загрузке вашего приложения; например, в методе 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
В более старых версиях движки шаблонов не реализовывали метод 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/5.2/topics/checks/