2014-03-03 11:56:11 +01:00
|
|
|
======================
|
|
|
|
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
|
2014-03-03 12:16:19 +01:00
|
|
|
can be provided, or the hint is self-evident from the error message, the
|
|
|
|
hint can be omitted, or a value of ``None`` can be used.
|
2014-03-03 11:56:11 +01:00
|
|
|
|
|
|
|
``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::
|
|
|
|
|
2014-09-12 20:50:36 +02:00
|
|
|
from django.core.checks import register, Tags
|
2014-03-03 11:56:11 +01:00
|
|
|
|
2014-09-12 20:50:36 +02:00
|
|
|
@register(Tags.compatibility)
|
2014-03-03 11:56:11 +01:00
|
|
|
def my_check(app_configs, **kwargs):
|
|
|
|
# ... perform compatibility checks and collect errors
|
|
|
|
return errors
|
|
|
|
|
2014-09-12 20:50:36 +02:00
|
|
|
.. versionadded:: 1.8
|
|
|
|
|
|
|
|
You can register "deployment checks" that are only relevant to a production
|
|
|
|
settings file like this::
|
|
|
|
|
|
|
|
@register(Tags.security, deploy=True)
|
|
|
|
def my_check(app_configs, **kwargs):
|
|
|
|
...
|
|
|
|
|
|
|
|
These checks will only be run if the :djadminopt:`--deploy` option is passed to
|
|
|
|
the :djadmin:`check` command.
|
|
|
|
|
2014-03-03 11:56:11 +01:00
|
|
|
.. _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.
|
2014-09-05 19:06:20 +02:00
|
|
|
It's recommended that you delegate each check to separate methods.
|
2014-03-03 11:56:11 +01:00
|
|
|
|
|
|
|
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
|