mirror of
https://github.com/django/django.git
synced 2025-10-31 09:41:08 +00:00
Added first cut at reference documentation for the checks framework.
This commit is contained in:
211
docs/topics/checks.txt
Normal file
211
docs/topics/checks.txt
Normal file
@@ -0,0 +1,211 @@
|
||||
======================
|
||||
System check framework
|
||||
======================
|
||||
|
||||
.. versionadded:: 1.7
|
||||
|
||||
.. module:: django.core.checks
|
||||
|
||||
The system check framework is a set of static checks for validating Django
|
||||
projects. It detects common problems and provides hints for how to fix them.
|
||||
The framework is extensible so you can easily add your own checks.
|
||||
|
||||
Checks can be triggered explicitly via the :djadmin:`check` command. Checks are
|
||||
triggered implicitly before most commands, including :djadmin:`runserver` and
|
||||
:djadmin:`migrate`. For performance reasons, the checks are not performed if
|
||||
:setting:`DEBUG` is set to ``False``.
|
||||
|
||||
Serious errors will prevent Django commands (such as :djadmin:`runserver`) from
|
||||
running at all. Minor problems are reported to the console. If you have inspected
|
||||
the cause of a warning and are happy to ignore it, you can hide specific warnings
|
||||
using the :setting:`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 the
|
||||
:doc:`System check reference </ref/checks>`.
|
||||
|
||||
Writing your own checks
|
||||
=======================
|
||||
|
||||
The framework is flexible and allows you to write functions that perform
|
||||
any other kind of check you may require. The following is an example stub
|
||||
check function::
|
||||
|
||||
from django.core.checks import register
|
||||
|
||||
@register()
|
||||
def example_check(app_configs, **kwargs):
|
||||
errors = []
|
||||
# ... your check logic here
|
||||
return errors
|
||||
|
||||
The check function *must* accept an ``app_configs`` argument; this argument is
|
||||
the list of applications that should be inspected. If None, the check must be
|
||||
run on *all* installed apps in the project. The ``**kwargs`` argument is required
|
||||
for future expansion.
|
||||
|
||||
Messages
|
||||
--------
|
||||
|
||||
The function must return a list of messages. If no problems are found as a result
|
||||
of the check, the check function must return an empty list.
|
||||
|
||||
.. class:: CheckMessage(level, msg, hint, obj=None, id=None)
|
||||
|
||||
The warnings and errors raised by the check method must be instances of
|
||||
:class:`~django.core.checks.CheckMessage`. An instance of
|
||||
:class:`~django.core.checks.CheckMessage` encapsulates a single reportable
|
||||
error or warning. It also provides context and hints applicable to the
|
||||
message, and a unique identifier that is used for filtering purposes.
|
||||
|
||||
The concept is very similar to messages from the :doc:`message
|
||||
framework </ref/contrib/messages>` or the :doc:`logging framework
|
||||
</topics/logging>`. Messages are tagged with a ``level`` indicating the
|
||||
severity of the message.
|
||||
|
||||
Constructor arguments are:
|
||||
|
||||
``level``
|
||||
The severity of the message. Use one of the
|
||||
predefined values: ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR``,
|
||||
``CRITICAL``. If the level is greater or equal to ``ERROR``, then Django
|
||||
will prevent management commands from executing. Messages with
|
||||
level lower than ``ERROR`` (i.e. warnings) are reported to the console,
|
||||
but can be silenced.
|
||||
|
||||
``msg``
|
||||
A short (less than 80 characters) string describing the problem. The string
|
||||
should *not* contain newlines.
|
||||
|
||||
``hint``
|
||||
A single-line string providing a hint for fixing the problem. If no hint
|
||||
can be provided, or the hint is self-evident from the error message, a
|
||||
value of ``None`` can be used::
|
||||
|
||||
Error('error message') # Will not work.
|
||||
Error('error message', None) # Good
|
||||
Error('error message', hint=None) # Better
|
||||
|
||||
``obj``
|
||||
Optional. An object providing context for the message (for example, the
|
||||
model where the problem was discovered). The object should be a model, field,
|
||||
or manager or any other object that defines ``__str__`` method (on
|
||||
Python 2 you need to define ``__unicode__`` method). The method is used while
|
||||
reporting all messages and its result precedes the message.
|
||||
|
||||
``id``
|
||||
Optional string. A unique identifier for the issue. Identifiers should
|
||||
follow the pattern ``applabel.X001``, where ``X`` is one of the letters
|
||||
``CEWID``, indicating the message severity (``C`` for criticals,
|
||||
``E`` for errors and so). The number can be allocated by the application,
|
||||
but should be unique within that application.
|
||||
|
||||
There are also shortcuts to make creating messages with common levels easier.
|
||||
When using these methods you can omit the ``level`` argument because it is
|
||||
implied by the class name.
|
||||
|
||||
.. class:: Debug(msg, hint, obj=None, id=None)
|
||||
.. class:: Info(msg, hint, obj=None, id=None)
|
||||
.. class:: Warning(msg, hint, obj=None, id=None)
|
||||
.. class:: Error(msg, hint, obj=None, id=None)
|
||||
.. class:: Critical(msg, hint, obj=None, id=None)
|
||||
|
||||
Messages are comparable. That allows you to easily write tests::
|
||||
|
||||
from django.core.checks import Error
|
||||
errors = checked_object.check()
|
||||
expected_errors = [
|
||||
Error(
|
||||
'an error',
|
||||
hint=None,
|
||||
obj=checked_object,
|
||||
id='myapp.E001',
|
||||
)
|
||||
]
|
||||
self.assertEqual(errors, expected_errors)
|
||||
|
||||
Registering and labeling checks
|
||||
-------------------------------
|
||||
|
||||
Lastly, your check function must be registered explicitly with system check
|
||||
registry.
|
||||
|
||||
.. function:: register(*tags)(function)
|
||||
|
||||
You can pass as many tags to ``register`` as you want in order to label your
|
||||
check. Tagging checks is useful since it allows you to run only a certain
|
||||
group of checks. For example, to register a compatibility check, you would
|
||||
make the following call::
|
||||
|
||||
from django.core.checks import register
|
||||
|
||||
@register('compatibility')
|
||||
def my_check(app_configs, **kwargs):
|
||||
# ... perform compatibility checks and collect errors
|
||||
return errors
|
||||
|
||||
.. _field-checking:
|
||||
|
||||
Field, Model, and Manager checks
|
||||
--------------------------------
|
||||
|
||||
In some cases, you won't need to register your check function -- you can
|
||||
piggyback on an existing registration.
|
||||
|
||||
Fields, models, and model managers all implement a ``check()`` method that is
|
||||
already registered with the check framework. If you want 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 generated by the base class.
|
||||
It's recommended the you delegate each check to a separate methods.
|
||||
|
||||
Consider an example where you are implementing a custom field named
|
||||
``RangedIntegerField``. This field adds ``min`` and ``max`` arguments to the
|
||||
constructor of ``IntegerField``. You may want to add a check to ensure that users
|
||||
provide a min value that is less than or equal to the max value. The following
|
||||
code snippet shows how you can implement this check::
|
||||
|
||||
from django.core import checks
|
||||
from django.db import models
|
||||
|
||||
class RangedIntegerField(models.IntegerField):
|
||||
def __init__(self, min=None, max=None, **kwargs):
|
||||
super(RangedIntegerField, self).__init__(**kwargs)
|
||||
self.min = min
|
||||
self.max = max
|
||||
|
||||
def check(self, **kwargs):
|
||||
# Call the superclass
|
||||
errors = super(RangedIntegerField, self).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 []
|
||||
|
||||
If you wanted to add checks to a model manager, you would take the same
|
||||
approach on your subclass of :class:`~django.db.models.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::
|
||||
|
||||
class MyModel(models.Model):
|
||||
@classmethod
|
||||
def check(cls, **kwargs):
|
||||
errors = super(MyModel, cls).check(**kwargs)
|
||||
# ... your own checks ...
|
||||
return errors
|
||||
Reference in New Issue
Block a user