Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added first cut at reference documentation for the checks framework.

  • Loading branch information...
commit 5679fce87c1eb2a48f0ea2ecefb08e2285828af0 1 parent 82ac389
@freakboy3742 freakboy3742 authored
View
2  docs/index.txt
@@ -293,7 +293,7 @@ Learn about some other core functionalities of the Django framework:
* :doc:`Flatpages <ref/contrib/flatpages>`
* :doc:`Redirects <ref/contrib/redirects>`
* :doc:`Signals <topics/signals>`
-* :doc:`System check framework <ref/checks>`
+* :doc:`System check framework <topics/checks>`
* :doc:`The sites framework <ref/contrib/sites>`
* :doc:`Unicode in Django <ref/unicode>`
View
416 docs/ref/checks.txt
@@ -4,205 +4,233 @@ 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
+For details on how to add your own checks and integrate them with Django`s
+system checks, see the :doc:`System check topic guide </topics/checks>`.
+
+Builtin tags
+------------
+
+Django's system checks are organized using the following tags:
+
+* ``models``: Checks governing model, field and manager definitions.
+* ``signals``: Checks on signal declarations and handler registrations.
+* ``admin``: Checks of any admin site declarations.
+
+Some checks may be registered with multiple tags.
+
+Core system checks
+------------------
+
+Models
+~~~~~~
+
+* **models.E001**: ``<swappable>`` is not of the form ``app_label.app_name``.
+* **models.E002**: ``<SETTING>`` references ``<model>``, which has not been installed, or is abstract.
+* **models.E003**: The model has two many-to-many relations through the intermediate model ``%s.%s``.
+* **models.E004**: ``id`` can only be used as a field name if the field also sets ``primary_key=True``.
+* **models.E005**: The field ``<field name>`` from parent model <model> clashes with the field ``<field name>`` from parent model <model>.
+* **models.E006**: The field clashes with the field ``<field name>`` from model <model>.
+* **models.E007**: Field ``<field name>`` has column name ``<column name>`` that is used by another field.
+* **models.E008**: ``index_together`` must be a list or tuple.
+* **models.E009**: All ``index_together`` elements must be lists or tuples.
+* **models.E010**: ``unique_together`` must be a list or tuple.
+* **models.E011**: All ``unique_together`` elements must be lists or tuples.
+* **models.E012**: ``index_together/unique_together`` refers to the non-existent field ``<field name>``.
+* **models.E013**: ``index_together/unique_together`` refers to a ManyToManyField ``<field name>``, but ManyToManyFields are not supported for that option.
+* **models.E014**: ``ordering`` must be a tuple or list (even if you want to order by only one field).
+* **models.E015**: ``ordering`` refers to the non-existent field ``<field name>``.
+
+Fields
+~~~~~~
+
+* **fields.E001**: Field names must not end with an underscore.
+* **fields.E002**: Field names must not contain "__".
+* **fields.E003**: ``pk`` is a reserved word that cannot be used as a field name.
+* **fields.E004**: ``choices`` must be an iterable (e.g., a list or tuple).
+* **fields.E005**: ``choices`` must be an iterable returning (actual value, human readable name) tuples.
+* **fields.E006**: ``db_index`` must be None, True or False.
+* **fields.E007**: Primary keys must not have null=True.
+* **fields.E100**: AutoFields must set primary_key=True.
+* **fields.E110**: BooleanFields do not accept null values.
+* **fields.E120**: CharFields must define a ``max_length`` attribute.
+* **fields.E121**: ``max_length`` must be a positive integer.
+* **fields.E130**: DecimalFields must define a ``decimal_places`` attribute.
+* **fields.E131**: ``decimal_places`` must be a non-negative integer.
+* **fields.E132**: DecimalFields must define a ``max_digits`` attribute.
+* **fields.E133**: ``max_digits`` must be a non-negative integer.
+* **fields.E134**: ``max_digits`` must be greater or equal to ``decimal_places``.
+* **fields.E140**: FilePathFields must have either ``allow_files`` or ``allow_folders`` set to True.
+* **fields.E150**: GenericIPAddressFields cannot accept blank values if null values are not allowed, as blank values are stored as nulls.
+
+File Fields
+~~~~~~~~~~~
+
+* **fields.E200**: ``unique`` is not a valid argument for a FileField.
+* **fields.E201**: ``primary_key`` is not a valid argument for a FileField.
+* **fields.E210**: Cannot use ImageField because Pillow is not installed.
+
+Related Fields
+~~~~~~~~~~~~~~
+
+* **fields.E300**: Field defines a relation with model ``<model>``, which is either not installed, or is abstract.
+* **fields.E301**: Field defines a relation with the model ``<model>`` which has been swapped out.
+* **fields.E302**: Accessor for field ``<field name>`` clashes with field ``<field name>``.
+* **fields.E303**: Reverse query name for field ``<field name>`` clashes with field ``<field name>``.
+* **fields.E304**: Field name ``<field name>`` clashes with accessor for ``<field name>``.
+* **fields.E305**: Field name ``<field name>`` clashes with reverse query name for ``<field name>``.
+* **fields.E310**: None of the fields ``<field1>``, ``<field2>``, ... on model ``<model>`` have a unique=True constraint.
+* **fields.E311**: ``<model>`` must set unique=True because it is referenced by a ForeignKey.
+* **fields.E320**: Field specifies on_delete=SET_NULL, but cannot be null.
+* **fields.E321**: The field specifies on_delete=SET_DEFAULT, but has no default value.
+* **fields.E330**: ManyToManyFields cannot be unique.
+* **fields.E331**: Field specifies a many-to-many relation through model ``%s``, which has not been installed.
+* **fields.E332**: Many-to-many fields with intermediate tables must not be symmetrical.
+* **fields.E333**: The model is used as an intermediate model by ``<model>``, but it has more than two foreign keys to ``<model>``, which is ambiguous.
+* **fields.E334**: The model is used as an intermediate model by ``<model>``, but it has more than one foreign key from ``<model>``, which is ambiguous.
+* **fields.E335**: The model is used as an intermediate model by ``<model>``, but it has more than one foreign key to ``<model>``, which is ambiguous.
+* **fields.E336**: The model is used as an intermediary model by ``<model>``, but it does not have foreign key to ``<model>`` or ``<model>``."
+
+Signals
+~~~~~~~
+
+* **signals.E001**: <handler> was connected to the ``<signal>`` signal with a lazy reference to the ``<moel>`` sender, which has not been installed.
+
+Admin
+-----
+
+Admin checks are all performed as part of the ``admin`` tag.
+
+The following checks are performend on any
+:class:`~django.contrib.admin.ModelAdmin` (or subclass) that is registered
+with the admin site:
+
+* **admin.E001**: The value of ``raw_id_fields`` must be a list or tuple.
+* **admin.E002**: The value of ``raw_id_fields[n]`` refers to ``<field name>``, which is not an attribute of ``<model>``.
+* **admin.E003**: The value of ``raw_id_fields[n]`` must be a ForeignKey or ManyToManyField.
+* **admin.E004**: The value of ``fields`` must be a list or tuple.
+* **admin.E005**: Both ``fieldsets`` and ``fields`` are specified.
+* **admin.E006**: The value of ``fields`` contains duplicate field(s).
+* **admin.E007**: The value of ``fieldsets`` must be a list or tuple.
+* **admin.E008**: The value of ``fieldsets[n]`` must be a list or tuple.
+* **admin.E009**: The value of ``fieldsets[n]`` must be of length 2.
+* **admin.E010**: The value of ``fieldsets[n][1]`` must be a dictionary.
+* **admin.E011**: The value of ``fieldsets[n][1]`` must contain the key ``fields``.
+* **admin.E012**: There are duplicate field(s) in ``fieldsets[n][1]``
+* **admin.E013**: ``fields[n]/fieldsets[n][m]`` cannot include the ManyToManyField ``<field name>``, because that field manually specifies a relationship model.
+* **admin.E014**: The value of ``exclude`` must be a list or tuple.
+* **admin.E015**: The value of ``exclude`` contains duplicate field(s).
+* **admin.E016**: The value of ``form`` must inherit from ``BaseModelForm``.
+* **admin.E017**: The value of ``filter_vertical`` must be a list or tuple.
+* **admin.E018**: The value of ``filter_horizontal`` must be a list or tuple.
+* **admin.E019**: The value of ``filter_vertical[n]/filter_vertical[n]`` refers to ``<field name>``, which is not an attribute of ``<model>``.
+* **admin.E020**: The value of ``filter_vertical[n]/filter_vertical[n]`` must be a ManyToManyField.
+* **admin.E021**: The value of ``radio_fields`` must be a dictionary.
+* **admin.E022**: The value of ``radio_fields`` refers to ``<field name>``, which is not an attribute of ``<model>``.
+* **admin.E023**: The value of ``radio_fields`` refers to ``<field name>``, which is not a ForeignKey, and does not have a ``choices`` definition.
+* **admin.E024**: The value of ``radio_fields[<field name>]`` must be either admin.HORIZONTAL nor admin.VERTICAL.
+* **admin.E025**: The value of ``view_on_site`` must be either a callable or a boolean value.
+* **admin.E026**: The value of ``prepopulated_fields`` must be a dictionary.
+* **admin.E027**: The value of ``prepopulated_fields`` refers to ``<field name>``, which is not an attribute of ``<model>``.
+* **admin.E028**: The value of ``prepopulated_fields`` refers to ``<field name>``, which must not be a DateTimeField, ForeignKey or ManyToManyField.
+* **admin.E029**: The value of ``prepopulated_fields[<field name>]`` must be a list or tuple.
+* **admin.E030**: The value of ``prepopulated_fields`` refers to ``<field name>``, which is not an attribute of ``<model>``.
+* **admin.E031**: The value of ``ordering`` must be a list or tuple.
+* **admin.E032**: The value of ``ordering`` has the random ordering marker ``?``, but contains other fields as well.
+* **admin.E033**: The value of ``ordering`` refers to ``<field name>``, which is not an attribute of ``<model>``.
+* **admin.E034**: The value of ``readonly_fields`` must be a list or tuple.
+* **admin.E035**: The value of ``readonly_fields[n]`` is not a callable, an attribute of ``<ModelAdmin class>``, or an attribute of ``<model>``.
+
+ModelAdmin
+~~~~~~~~~~
+
+The following checks are performed on any
+:class:`~django.contrib.admin.ModelAdmin` that is registered
+with the admin site:
+
+* **admin.E101**: The value of ``save_as`` must be a boolean.
+* **admin.E102**: The value of ``save_on_top`` must be a boolean.
+* **admin.E103**: The value of ``inlines`` must be a list or tuple.
+* **admin.E104**: ``<InlineModelAdmin class>`` must inherit from ``BaseModelAdmin``.
+* **admin.E105**: ``<InlineModelAdmin class>`` must have a ``model`` attribute.
+* **admin.E106**: The value of ``<InlineModelAdmin class>.model`` must be a Model.
+* **admin.E107**: The value of ``list_display`` must be a list or tuple.
+* **admin.E108**: The value of ``list_display[n]`` refers to ``<label>``, which is not a callable, an attribute of ``<ModelAdmin class``, or an attribute or method on ``<model>``.
+* **admin.E109**: The value of ``list_display[n]`` must not be a ManyToManyField.
+* **admin.E110**: The value of ``list_display_links`` must be a list, a tuple, or None.
+* **admin.E111**: The value of ``list_display_links[n]`` refers to ``<label>``, which is not defined in ``list_display``.
+* **admin.E112**: The value of ``list_filter`` must be a list or tuple.
+* **admin.E113**: The value of ``list_filter[n]`` must inherit from ``ListFilter``.
+* **admin.E114**: The value of ``list_filter[n]`` must not inherit from ``FieldListFilter``.
+* **admin.E115**: The value of ``list_filter[n][1]`` must inherit from ``FieldListFilter``.
+* **admin.E116**: The value of ``list_filter[n]`` refers to ``<label>``, which does not refer to a Field.
+* **admin.E117**: The value of ``list_select_related`` must be a boolean, tuple or list.
+* **admin.E118**: The value of ``list_per_page`` must be an integer.
+* **admin.E119**: The value of ``list_max_show_all`` must be an integer.
+* **admin.E120**: The value of ``list_editable`` must be a list or tuple.
+* **admin.E121**: The value of ``list_editable[n]`` refers to ``<label>``, which is not an attribute of ``<model>``.
+* **admin.E122**: The value of ``list_editable[n]`` refers to ``<label>``, which is not contained in ``list_display``.
+* **admin.E123**: The value of ``list_editable[n]`` cannot be in both ``list_editable`` and ``list_display_links``.
+* **admin.E124**: The value of ``list_editable[n]`` refers to the first field in ``list_display`` (``<label>``), which cannot be used unless ``list_display_links`` is set.
+* **admin.E125**: The value of ``list_editable[n]`` refers to ``<field name>``, which is not editable through the admin.
+* **admin.E126**: The value of ``search_fields`` must be a list or tuple.
+* **admin.E127**: The value of ``date_hierarchy`` refers to ``<field name>``, which is not an attribute of ``<model>``.
+* **admin.E128**: The value of ``date_hierarchy`` must be a DateField or DateTimeField.
+
+InlineModelAdmin
+~~~~~~~~~~~~~~~~
+
+The following checks are performed on any
+:class:`~django.contrib.admin.InlineModelAdmin` that is registered as an
+inline on a :class:`~django.contrib.admin.ModelAdmin`.
+
+* **admin.E201**: Cannot exclude the field ``<field name>``, because it is the foreign key to the parent model ``%s.%s``.
+* **admin.E202**: ``<model>`` has more than one ForeignKey to ``<parent model>``.
+* **admin.E203**: The value of ``extra`` must be an integer.
+* **admin.E204**: The value of ``max_num`` must be an integer.
+* **admin.E205**: The value of ``formset`` must inherit from ``BaseModelFormSet``.
+
+
+Auth
+----
+
+* **auth.E001**: ``REQUIRED_FIELDS`` must be a list or tuple.
+* **auth.E002**: The field named as the ``USERNAME_FIELD`` for a custom user model must not be included in ``REQUIRED_FIELDS``.
+* **auth.E003**: ``<field>`` must be unique because it is named as the ``USERNAME_FIELD``.
+* **auth.W004**: ``<field>`` is named as the ``USERNAME_FIELD``, but it is not unique.
+
+
+Content Types
+-------------
+
+The following checks are performed when a model contains a
+:class:`~django.contrib.contenttypes.fields.GenericForeignKey` or
+:class:`~django.contrib.contenttypes.fields.GenericRelation`:
+
+* **contenttypes.E001**: The GenericForeignKey object ID references the non-existent field ``<field>``
+* **contenttypes.E002**: The GenericForeignKey content type references the non-existent field ``<field>``
+* **contenttypes.E003**: ``<field>`` is not a ForeignKey.
+* **contenttypes.E004**: ``<field>`` is not a ForeignKey to ``contenttypes.ContentType``
+
+Sites
+-----
+
+The following checks are performed on any model using a
+:class:`~django.contrib.sites.managers.CurrentSiteManager`:
+
+* **sites.E001**: CurrentSiteManager could not find a field named ``<field name>``.
+* **sites.E002**: CurrentSiteManager cannot use ``<field>`` as it is not a ForeignKey or ManyToManyField.
+
+Database
+--------
- @register()
- def example_check(app_configs, **kwargs):
- errors = []
- # ... your check logic here
- return errors
+MySQL
+~~~~~
-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.
+If you're using MySQL, the following checks will be performed:
-Messages
---------
+* **mysql.E001**: MySQL does not allow unique CharFields to have a max_length > 255.
-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
View
211 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
View
1  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
Please sign in to comment.
Something went wrong with that request. Please try again.