Система проверки фреймворка
Система проверки фреймворка — это набор статических проверок для валидации проектов 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, так как он подразумевается именем класса.
Регистрация и маркировка проверок
Наконец, ваша функция проверки должна быть явно зарегистрирована в реестре системных проверок. Проверки должны быть зарегистрированы в файле, загружаемом при загрузке вашего приложения; например, в методе 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/