Added first cut at reference documentation for the checks framework.
This commit is contained in:
parent
82ac389486
commit
5679fce87c
|
@ -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>`
|
||||
|
||||
|
|
|
@ -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``.
|
||||
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>`.
|
||||
|
||||
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.
|
||||
Builtin tags
|
||||
------------
|
||||
|
||||
Writing your own checks
|
||||
=======================
|
||||
Django's system checks are organized using the following tags:
|
||||
|
||||
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::
|
||||
* ``models``: Checks governing model, field and manager definitions.
|
||||
* ``signals``: Checks on signal declarations and handler registrations.
|
||||
* ``admin``: Checks of any admin site declarations.
|
||||
|
||||
from django.core.checks import register
|
||||
Some checks may be registered with multiple tags.
|
||||
|
||||
@register()
|
||||
def example_check(app_configs, **kwargs):
|
||||
errors = []
|
||||
# ... your check logic here
|
||||
return errors
|
||||
Core system checks
|
||||
------------------
|
||||
|
||||
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.
|
||||
Models
|
||||
~~~~~~
|
||||
|
||||
Messages
|
||||
* **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
|
||||
--------
|
||||
|
||||
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.
|
||||
MySQL
|
||||
~~~~~
|
||||
|
||||
.. class:: CheckMessage(level, msg, hint, obj=None, id=None)
|
||||
If you're using MySQL, the following checks will be performed:
|
||||
|
||||
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.
|
||||
* **mysql.E001**: MySQL does not allow unique CharFields to have a max_length > 255.
|
||||
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -30,3 +30,4 @@ Introductions to all the key parts of Django you'll need to know:
|
|||
serialization
|
||||
settings
|
||||
signals
|
||||
checks
|
||||
|
|
Loading…
Reference in New Issue