summaryrefslogtreecommitdiff
path: root/docs/topics
diff options
context:
space:
mode:
authorRussell Keith-Magee <russell@keith-magee.com>2014-03-03 18:56:11 +0800
committerRussell Keith-Magee <russell@keith-magee.com>2014-03-03 18:56:11 +0800
commit5679fce87c1eb2a48f0ea2ecefb08e2285828af0 (patch)
tree972aa9d60fb4d70bfe1a295c7053eb6e51812e65 /docs/topics
parent82ac3894867b111f83252e808b3ed47f38ef5378 (diff)
Added first cut at reference documentation for the checks framework.
Diffstat (limited to 'docs/topics')
-rw-r--r--docs/topics/checks.txt211
-rw-r--r--docs/topics/index.txt1
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