Refs #26351 -- Added check hook to support database-related checks
Thanks Tim Graham and Shai Berger for the reviews.
This commit is contained in:
parent
5ac7c8f7ab
commit
0d3c616fbb
|
@ -10,6 +10,7 @@ from .registry import Tags, register, run_checks, tag_exists
|
||||||
# Import these to force registration of checks
|
# Import these to force registration of checks
|
||||||
import django.core.checks.caches # NOQA isort:skip
|
import django.core.checks.caches # NOQA isort:skip
|
||||||
import django.core.checks.compatibility.django_1_8_0 # NOQA isort:skip
|
import django.core.checks.compatibility.django_1_8_0 # NOQA isort:skip
|
||||||
|
import django.core.checks.database # NOQA isort:skip
|
||||||
import django.core.checks.model_checks # NOQA isort:skip
|
import django.core.checks.model_checks # NOQA isort:skip
|
||||||
import django.core.checks.security.base # NOQA isort:skip
|
import django.core.checks.security.base # NOQA isort:skip
|
||||||
import django.core.checks.security.csrf # NOQA isort:skip
|
import django.core.checks.security.csrf # NOQA isort:skip
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
from django.db import connections
|
||||||
|
|
||||||
|
from . import Tags, register
|
||||||
|
|
||||||
|
|
||||||
|
@register(Tags.database)
|
||||||
|
def check_database_backends(*args, **kwargs):
|
||||||
|
issues = []
|
||||||
|
for conn in connections.all():
|
||||||
|
issues.extend(conn.validation.check(**kwargs))
|
||||||
|
return issues
|
|
@ -13,6 +13,7 @@ class Tags(object):
|
||||||
admin = 'admin'
|
admin = 'admin'
|
||||||
caches = 'caches'
|
caches = 'caches'
|
||||||
compatibility = 'compatibility'
|
compatibility = 'compatibility'
|
||||||
|
database = 'database'
|
||||||
models = 'models'
|
models = 'models'
|
||||||
security = 'security'
|
security = 'security'
|
||||||
signals = 'signals'
|
signals = 'signals'
|
||||||
|
@ -70,6 +71,11 @@ class CheckRegistry(object):
|
||||||
if tags is not None:
|
if tags is not None:
|
||||||
checks = [check for check in checks
|
checks = [check for check in checks
|
||||||
if hasattr(check, 'tags') and set(check.tags) & set(tags)]
|
if hasattr(check, 'tags') and set(check.tags) & set(tags)]
|
||||||
|
else:
|
||||||
|
# By default, 'database'-tagged checks are not run as they do more
|
||||||
|
# than mere static code analysis.
|
||||||
|
checks = [check for check in checks
|
||||||
|
if not hasattr(check, 'tags') or Tags.database not in check.tags]
|
||||||
|
|
||||||
for check in checks:
|
for check in checks:
|
||||||
new_errors = check(app_configs=app_configs)
|
new_errors = check(app_configs=app_configs)
|
||||||
|
|
|
@ -368,6 +368,9 @@ class BaseCommand(object):
|
||||||
translation.activate(saved_locale)
|
translation.activate(saved_locale)
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
def _run_checks(self, **kwargs):
|
||||||
|
return checks.run_checks(**kwargs)
|
||||||
|
|
||||||
def check(self, app_configs=None, tags=None, display_num_errors=False,
|
def check(self, app_configs=None, tags=None, display_num_errors=False,
|
||||||
include_deployment_checks=False, fail_level=checks.ERROR):
|
include_deployment_checks=False, fail_level=checks.ERROR):
|
||||||
"""
|
"""
|
||||||
|
@ -376,7 +379,7 @@ class BaseCommand(object):
|
||||||
If there are only light messages (like warnings), they are printed to
|
If there are only light messages (like warnings), they are printed to
|
||||||
stderr and no exception is raised.
|
stderr and no exception is raised.
|
||||||
"""
|
"""
|
||||||
all_issues = checks.run_checks(
|
all_issues = self._run_checks(
|
||||||
app_configs=app_configs,
|
app_configs=app_configs,
|
||||||
tags=tags,
|
tags=tags,
|
||||||
include_deployment_checks=include_deployment_checks,
|
include_deployment_checks=include_deployment_checks,
|
||||||
|
|
|
@ -6,6 +6,7 @@ from collections import OrderedDict
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
|
from django.core.checks import Tags, run_checks
|
||||||
from django.core.management.base import BaseCommand, CommandError
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
from django.core.management.sql import (
|
from django.core.management.sql import (
|
||||||
emit_post_migrate_signal, emit_pre_migrate_signal,
|
emit_post_migrate_signal, emit_pre_migrate_signal,
|
||||||
|
@ -56,6 +57,11 @@ class Command(BaseCommand):
|
||||||
help='Creates tables for apps without migrations.',
|
help='Creates tables for apps without migrations.',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _run_checks(self, **kwargs):
|
||||||
|
issues = run_checks(tags=[Tags.database])
|
||||||
|
issues.extend(super(Command, self).check(**kwargs))
|
||||||
|
return issues
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
|
||||||
self.verbosity = options['verbosity']
|
self.verbosity = options['verbosity']
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
class BaseDatabaseValidation(object):
|
class BaseDatabaseValidation(object):
|
||||||
"""
|
"""
|
||||||
This class encapsulates all backend-specific model validation.
|
This class encapsulates all backend-specific validation.
|
||||||
"""
|
"""
|
||||||
def __init__(self, connection):
|
def __init__(self, connection):
|
||||||
self.connection = connection
|
self.connection = connection
|
||||||
|
|
||||||
|
def check(self, **kwargs):
|
||||||
|
return []
|
||||||
|
|
||||||
def check_field(self, field, **kwargs):
|
def check_field(self, field, **kwargs):
|
||||||
return []
|
return []
|
||||||
|
|
|
@ -84,6 +84,14 @@ Django's system checks are organized using the following tags:
|
||||||
* ``templates``: Checks template related configuration.
|
* ``templates``: Checks template related configuration.
|
||||||
* ``caches``: Checks cache related configuration.
|
* ``caches``: Checks cache related configuration.
|
||||||
* ``urls``: Checks URL configuration.
|
* ``urls``: Checks URL configuration.
|
||||||
|
* ``database``: Checks database-related configuration issues. Database checks
|
||||||
|
are not run by default because they do more than static code analysis as
|
||||||
|
regular checks do. They are only run by the :djadmin:`migrate` command or if
|
||||||
|
you specify the ``database`` tag when calling the :djadmin:`check` command.
|
||||||
|
|
||||||
|
.. versionadded:: 1.10
|
||||||
|
|
||||||
|
The ``database`` tag was added.
|
||||||
|
|
||||||
Some checks may be registered with multiple tags.
|
Some checks may be registered with multiple tags.
|
||||||
|
|
||||||
|
|
|
@ -120,17 +120,22 @@ The code below is equivalent to the code above::
|
||||||
|
|
||||||
.. _field-checking:
|
.. _field-checking:
|
||||||
|
|
||||||
Field, model, and manager checks
|
Field, model, manager, and database checks
|
||||||
--------------------------------
|
------------------------------------------
|
||||||
|
|
||||||
In some cases, you won't need to register your check function -- you can
|
In some cases, you won't need to register your check function -- you can
|
||||||
piggyback on an existing registration.
|
piggyback on an existing registration.
|
||||||
|
|
||||||
Fields, models, and model managers all implement a ``check()`` method that is
|
Fields, models, model managers, and database backends all implement a
|
||||||
already registered with the check framework. If you want to add extra checks,
|
``check()`` method that is already registered with the check framework. If you
|
||||||
you can extend the implementation on the base class, perform any extra
|
want to add extra checks, you can extend the implementation on the base class,
|
||||||
checks you need, and append any messages to those generated by the base class.
|
perform any extra checks you need, and append any messages to those generated
|
||||||
It's recommended that you delegate each check to separate methods.
|
by the base class. It's recommended that you delegate each check to separate
|
||||||
|
methods.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.10
|
||||||
|
|
||||||
|
Database backend checks were added.
|
||||||
|
|
||||||
Consider an example where you are implementing a custom field named
|
Consider an example where you are implementing a custom field named
|
||||||
``RangedIntegerField``. This field adds ``min`` and ``max`` arguments to the
|
``RangedIntegerField``. This field adds ``min`` and ``max`` arguments to the
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from django.core.checks import Tags, run_checks
|
||||||
|
from django.core.checks.registry import CheckRegistry
|
||||||
|
from django.db import connection
|
||||||
|
from django.test import TestCase, mock
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseCheckTests(TestCase):
|
||||||
|
@property
|
||||||
|
def func(self):
|
||||||
|
from django.core.checks.database import check_database_backends
|
||||||
|
return check_database_backends
|
||||||
|
|
||||||
|
def test_database_checks_not_run_by_default(self):
|
||||||
|
"""
|
||||||
|
`database` checks are only run when their tag is specified.
|
||||||
|
"""
|
||||||
|
def f1(**kwargs):
|
||||||
|
return [5]
|
||||||
|
|
||||||
|
registry = CheckRegistry()
|
||||||
|
registry.register(Tags.database)(f1)
|
||||||
|
errors = registry.run_checks()
|
||||||
|
self.assertEqual(errors, [])
|
||||||
|
|
||||||
|
errors2 = registry.run_checks(tags=[Tags.database])
|
||||||
|
self.assertEqual(errors2, [5])
|
||||||
|
|
||||||
|
def test_database_checks_called(self):
|
||||||
|
with mock.patch('django.db.backends.base.validation.BaseDatabaseValidation.check') as mocked_check:
|
||||||
|
run_checks(tags=[Tags.database])
|
||||||
|
self.assertTrue(mocked_check.called)
|
Loading…
Reference in New Issue