系统检查框架

系统检查框架是一组验证Django项目的静态检查。 它检测到常见的问题,并提供了如何解决这些问题的提示。 该框架是可扩展的,所以你可以轻松地添加自己的检查。

Checks can be triggered explicitly via the check command. Checks aretriggered implicitly before most commands, including runserver andmigrate. For performance reasons, checks are not run as part of theWSGI stack that is used in deployment. If you need to run system checks on yourdeployment server, trigger them explicitly using check.

Serious errors will prevent Django commands (such as runserver) fromrunning at all. Minor problems are reported to the console. If you have inspectedthe cause of a warning and are happy to ignore it, you can hide specific warningsusing the SILENCED_SYSTEM_CHECKS setting in your project settings file.

A full list of all checks that can be raised by Django can be found in theSystem check reference.

Writing your own checks

The framework is flexible and allows you to write functions that performany other kind of check you may require. The following is an example stubcheck function:

  1. from django.core.checks import Error, register
  2.  
  3. @register()
  4. def example_check(app_configs, **kwargs):
  5. errors = []
  6. # ... your check logic here
  7. if check_failed:
  8. errors.append(
  9. Error(
  10. 'an error',
  11. hint='A hint.',
  12. obj=checked_object,
  13. id='myapp.E001',
  14. )
  15. )
  16. return errors

The check function must accept an appconfigs argument; this argument isthe list of applications that should be inspected. If None, the check must berun on _all installed apps in the project. The **kwargs argument is requiredfor future expansion.

消息

The function must return a list of messages. If no problems are found as a resultof the check, the check function must return an empty list.

The warnings and errors raised by the check method must be instances ofCheckMessage. An instance ofCheckMessage encapsulates a single reportableerror or warning. It also provides context and hints applicable to themessage, and a unique identifier that is used for filtering purposes.

The concept is very similar to messages from the message framework or the logging framework.Messages are tagged with a level indicating the severity of the message.

There are also shortcuts to make creating messages with common levels easier.When using these classes you can omit the level argument because it isimplied by the class name.

Registering and labeling checks

Lastly, your check function must be registered explicitly with system checkregistry. Checks should be registered in a file that's loaded when yourapplication is loaded; for example, in the AppConfig.ready() method.

  • register(*tags)(function)
  • You can pass as many tags to register as you want in order to label yourcheck. Tagging checks is useful since it allows you to run only a certaingroup of checks. For example, to register a compatibility check, you wouldmake the following call:
  1. from django.core.checks import register, Tags
  2.  
  3. @register(Tags.compatibility)
  4. def my_check(app_configs, **kwargs):
  5. # ... perform compatibility checks and collect errors
  6. return errors

You can register "deployment checks" that are only relevant to a productionsettings file like this:

  1. @register(Tags.security, deploy=True)def my_check(app_configs, **kwargs):

These checks will only be run if the check —deploy option is used.

You can also use register as a function rather than a decorator bypassing a callable object (usually a function) as the first argumentto register.

The code below is equivalent to the code above:

  1. def my_check(app_configs, **kwargs):
  2. ...
  3. register(my_check, Tags.security, deploy=True)

Field, model, manager, and database checks

In some cases, you won't need to register your check function — you canpiggyback on an existing registration.

Fields, models, model managers, and database backends all implement acheck() method that is already registered with the check framework. If youwant to add extra checks, you can extend the implementation on the base class,perform any extra checks you need, and append any messages to those generatedby the base class. It's recommended that you delegate each check to separatemethods.

Consider an example where you are implementing a custom field namedRangedIntegerField. This field adds min and max arguments to theconstructor of IntegerField. You may want to add a check to ensure that usersprovide a min value that is less than or equal to the max value. The followingcode snippet shows how you can implement this check:

  1. from django.core import checks
  2. from django.db import models
  3.  
  4. class RangedIntegerField(models.IntegerField):
  5. def __init__(self, min=None, max=None, **kwargs):
  6. super().__init__(**kwargs)
  7. self.min = min
  8. self.max = max
  9.  
  10. def check(self, **kwargs):
  11. # Call the superclass
  12. errors = super().check(**kwargs)
  13.  
  14. # Do some custom checks and add messages to `errors`:
  15. errors.extend(self._check_min_max_values(**kwargs))
  16.  
  17. # Return all errors and warnings
  18. return errors
  19.  
  20. def _check_min_max_values(self, **kwargs):
  21. if (self.min is not None and
  22. self.max is not None and
  23. self.min > self.max):
  24. return [
  25. checks.Error(
  26. 'min greater than max.',
  27. hint='Decrease min or increase max.',
  28. obj=self,
  29. id='myapp.E001',
  30. )
  31. ]
  32. # When no error, return an empty list
  33. return []

If you wanted to add checks to a model manager, you would take the sameapproach on your subclass of Manager.

If you want to add a check to a model class, the approach is almost the same:the only difference is that the check is a classmethod, not an instance method:

  1. class MyModel(models.Model):
  2. @classmethod
  3. def check(cls, **kwargs):
  4. errors = super().check(**kwargs)
  5. # ... your own checks ...
  6. return errors

Writing tests

Messages are comparable. That allows you to easily write tests:

  1. from django.core.checks import Error
  2. errors = checked_object.check()
  3. expected_errors = [
  4. Error(
  5. 'an error',
  6. hint='A hint.',
  7. obj=checked_object,
  8. id='myapp.E001',
  9. )
  10. ]
  11. self.assertEqual(errors, expected_errors)