Фреймворк проверки¶
Фреймворк проверки это набор статических тестов для проверки проектов Django . Он обнаруживает распространенные проблемы и дает советы по их исправлению. Этот фреймворк расширяемый, поэтому вы можете легко добавлять свои собственные проверки.
Проверки могут быть вызваны явно через команду check. Проверки вызываются явно до большинства команд, включая runserver и migrate. По соображениям производительности, проверки не запускаются как часть стека WSGI, который используется при развертывании. Если необходимо выполнить проверки на сервере, на котором развертывается приложение, вызовите их явно, используя команду check.
Серьезные ошибки не позволят выполниться командам Django (таким как runserver). Незначительные проблемы будут выведены на консоль. Если Вы уже выявили причину предупреждения и хотите ее проигнорировать, Вы можете убрать определенные предупреждения, используя параметр SILENCED_SYSTEM_CHECKS в файле настроек проекта.
Полный список всех проверок, которые могут быть вызваны Django, можно найти в System check reference.
Создание собственных проверок¶
Фреймворк является гибким и позволяет создавать функции, выполняющие любые виды проверок, которые могут понадобиться. Далее представлен пример функции-заглушки для проверки:
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; этот аргумент представляет собой список приложений, которые следует проверить. Если указано значение «Нет», проверка должна выполняться для всех установленных приложений в проекте.
Проверка получит аргумент ключевого слова databases. Это список псевдонимов баз данных, соединения которых можно использовать для проверки конфигурации уровня базы данных. Если databases имеет значение None, проверка не должна использовать какие-либо соединения с базами данных.
Аргумент **kwargs необходим для будущего расширения.
Сообщения¶
Функция должна вернуть список сообщений. Если в ходе проверки не найдены проблемы, то функция возвращает пустой список
Предупреждения и ошибки вызванные проверочным методом должны быть экземплярами класса CheckMessage. Экземпляр CheckMessage содержит одну ошибку или предупреждение. Он также предоставляет контекст и советы применимые к сообщению. А также уникальный идентификатор, которой используется для фильтрации.
Идея очень похожа на сообщения message framework или logging framework. Тег 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
Вы можете регистрировать «deployment checks» , которые уместны только для настроек сервера:
@register(Tags.security, deploy=True)
def my_check(app_configs, **kwargs): ...
Эти проверки будут запускаться если используется опция --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())