mirror of
https://github.com/django/django.git
synced 2024-12-25 18:46:22 +00:00
d818e0c9b2
This is the result of Christopher Medrela's 2013 Summer of Code project. Thanks also to Preston Holmes, Tim Graham, Anssi Kääriäinen, Florian Apolloner, and Alex Gaynor for review notes along the way. Also: Fixes #8579, fixes #3055, fixes #19844.
209 lines
7.9 KiB
Plaintext
209 lines
7.9 KiB
Plaintext
======================
|
|
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.
|
|
|
|
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 implemenation 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 greated 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 sublass 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
|