System check framework

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 check command. Checks are triggered implicitly before most commands, including runserver and migrate. For performance reasons, checks are not run as part of the WSGI stack that is used in deployment. If you need to run system checks on your deployment server, trigger them explicitly using check.

Serious errors will prevent Django commands (such as 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 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 System check reference.

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 CheckMessage. An instance of 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 message framework or the logging framework. 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, the hint can be omitted, or a value of None can be used.
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.

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, Tags

@register(Tags.compatibility)
def my_check(app_configs, **kwargs):
    # ... perform compatibility checks and collect errors
    return errors
New in Django 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 --deploy option is passed to the check command.

You can also use register as a function rather than a decorator by passing a callable object (usually a function) as the first argument to register.

The code below is equivalent to the code above:

def my_check(app_configs, **kwargs):
    ...
register(my_check, Tags.security, deploy=True)
Changed in Django 1.8:

The ability to use register as a function was added.

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 that you delegate each check to 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 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
Back to Top