diff options
| author | Russell Keith-Magee <russell@keith-magee.com> | 2014-03-03 18:56:11 +0800 |
|---|---|---|
| committer | Russell Keith-Magee <russell@keith-magee.com> | 2014-03-03 18:56:11 +0800 |
| commit | 5679fce87c1eb2a48f0ea2ecefb08e2285828af0 (patch) | |
| tree | 972aa9d60fb4d70bfe1a295c7053eb6e51812e65 /docs/topics | |
| parent | 82ac3894867b111f83252e808b3ed47f38ef5378 (diff) | |
Added first cut at reference documentation for the checks framework.
Diffstat (limited to 'docs/topics')
| -rw-r--r-- | docs/topics/checks.txt | 211 | ||||
| -rw-r--r-- | docs/topics/index.txt | 1 |
2 files changed, 212 insertions, 0 deletions
diff --git a/docs/topics/checks.txt b/docs/topics/checks.txt new file mode 100644 index 0000000000..cf262811e6 --- /dev/null +++ b/docs/topics/checks.txt @@ -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 diff --git a/docs/topics/index.txt b/docs/topics/index.txt index 711bc09c13..e27f28112b 100644 --- a/docs/topics/index.txt +++ b/docs/topics/index.txt @@ -30,3 +30,4 @@ Introductions to all the key parts of Django you'll need to know: serialization settings signals + checks |
