Skip to content

Commit fe74d9b

Browse files
committed
Remove automatic setup feature
The middleware check was moved to apps.py and changed to use the system checks framework. It was updated to check MIDDLEWARE in addition to MIDDLEWARE_CLASSES. It now checks that DebugToolbarMiddleware occurs in one of the settings. Updated installation documentation to reflect new requirements. The bundled example project was updated to current Django and Debug Toolbar configuration recommendations. Fixes #838
1 parent d27f4ff commit fe74d9b

File tree

9 files changed

+165
-166
lines changed

9 files changed

+165
-166
lines changed

debug_toolbar/apps.py

+55-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,66 @@
11
from __future__ import absolute_import, unicode_literals
22

33
from django.apps import AppConfig
4+
from django.conf import settings
5+
from django.core.checks import Error, register
6+
from django.middleware.gzip import GZipMiddleware
7+
from django.utils.module_loading import import_string
48
from django.utils.translation import ugettext_lazy as _
59

6-
from debug_toolbar import settings as dt_settings
10+
from debug_toolbar.middleware import DebugToolbarMiddleware
711

812

913
class DebugToolbarConfig(AppConfig):
1014
name = 'debug_toolbar'
1115
verbose_name = _("Debug Toolbar")
1216

13-
def ready(self):
14-
if dt_settings.get_patch_settings():
15-
dt_settings.patch_all()
16-
dt_settings.check_middleware()
17+
18+
@register
19+
def check_middleware(app_configs, **kwargs):
20+
errors = []
21+
gzip_index = None
22+
debug_toolbar_index = None
23+
24+
setting = getattr(settings, 'MIDDLEWARE', None)
25+
setting_name = 'MIDDLEWARE'
26+
if setting is None:
27+
setting = settings.MIDDLEWARE_CLASSES
28+
setting_name = 'MIDDLEWARE_CLASSES'
29+
30+
# Determine the indexes which gzip and/or the toolbar are installed at
31+
for i, middleware in enumerate(setting):
32+
if is_middleware_class(GZipMiddleware, middleware):
33+
gzip_index = i
34+
elif is_middleware_class(DebugToolbarMiddleware, middleware):
35+
debug_toolbar_index = i
36+
37+
if debug_toolbar_index is None:
38+
# If the toolbar does not appear, report an error.
39+
errors.append(
40+
Error(
41+
"debug_toolbar.middleware.DebugToolbarMiddleware is missing "
42+
"from %s." % setting_name,
43+
hint="Add debug_toolbar.middleware.DebugToolbarMiddleware to "
44+
"%s." % setting_name,
45+
)
46+
)
47+
elif gzip_index is not None and debug_toolbar_index < gzip_index:
48+
# If the toolbar appears before the gzip index, report an error.
49+
errors.append(
50+
Error(
51+
"debug_toolbar.middleware.DebugToolbarMiddleware occurs before "
52+
"django.middleware.gzip.GZipMiddleware in %s." % setting_name,
53+
hint="Move debug_toolbar.middleware.DebugToolbarMiddleware to "
54+
"after django.middleware.gzip.GZipMiddleware in %s." % setting_name,
55+
)
56+
)
57+
58+
return errors
59+
60+
61+
def is_middleware_class(middleware_class, middleware_path):
62+
try:
63+
middleware_cls = import_string(middleware_path)
64+
except ImportError:
65+
return
66+
return issubclass(middleware_cls, middleware_class)

debug_toolbar/settings.py

-86
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
from __future__ import absolute_import, unicode_literals
22

33
import warnings
4-
from importlib import import_module
54

65
from django.conf import settings
76
from django.utils import six
87
from django.utils.lru_cache import lru_cache
9-
from django.utils.module_loading import import_string
108

119
# Always import this module as follows:
1210
# from debug_toolbar import settings [as dt_settings]
@@ -157,87 +155,3 @@ def get_panels():
157155
"setting." % (old_panel, new_panel), DeprecationWarning)
158156
PANELS[index] = new_panel
159157
return PANELS
160-
161-
162-
@lru_cache()
163-
def get_patch_settings():
164-
return getattr(settings, 'DEBUG_TOOLBAR_PATCH_SETTINGS', settings.DEBUG)
165-
166-
167-
# The following functions can monkey-patch settings automatically. Several
168-
# imports are placed inside functions to make it safe to import this module.
169-
170-
171-
def check_middleware():
172-
from django.middleware.gzip import GZipMiddleware
173-
from debug_toolbar.middleware import DebugToolbarMiddleware
174-
gzip_index = None
175-
debug_toolbar_index = None
176-
177-
# Determine the indexes which gzip and/or the toolbar are installed at
178-
for i, middleware in enumerate(settings.MIDDLEWARE_CLASSES):
179-
if is_middleware_class(GZipMiddleware, middleware):
180-
gzip_index = i
181-
elif is_middleware_class(DebugToolbarMiddleware, middleware):
182-
debug_toolbar_index = i
183-
# If the toolbar appears before the gzip index, raise a warning
184-
if gzip_index is not None and debug_toolbar_index < gzip_index:
185-
warnings.warn(
186-
"Please use an explicit setup with the "
187-
"debug_toolbar.middleware.DebugToolbarMiddleware "
188-
"after django.middleware.gzip.GZipMiddlware "
189-
"in MIDDLEWARE_CLASSES.", Warning)
190-
191-
192-
def is_middleware_class(middleware_class, middleware_path):
193-
try:
194-
middleware_cls = import_string(middleware_path)
195-
except ImportError:
196-
return
197-
return issubclass(middleware_cls, middleware_class)
198-
199-
200-
def is_toolbar_middleware_installed():
201-
from debug_toolbar.middleware import DebugToolbarMiddleware
202-
return any(is_middleware_class(DebugToolbarMiddleware, middleware)
203-
for middleware in settings.MIDDLEWARE_CLASSES)
204-
205-
206-
def prepend_to_setting(setting_name, value):
207-
"""Insert value at the beginning of a list or tuple setting."""
208-
values = getattr(settings, setting_name)
209-
# Make a list [value] or tuple (value,)
210-
value = type(values)((value,))
211-
setattr(settings, setting_name, value + values)
212-
213-
214-
def patch_internal_ips():
215-
if not settings.INTERNAL_IPS:
216-
prepend_to_setting('INTERNAL_IPS', '127.0.0.1')
217-
prepend_to_setting('INTERNAL_IPS', '::1')
218-
219-
220-
def patch_middleware_classes():
221-
if not is_toolbar_middleware_installed():
222-
prepend_to_setting('MIDDLEWARE_CLASSES',
223-
'debug_toolbar.middleware.DebugToolbarMiddleware')
224-
225-
226-
def patch_root_urlconf():
227-
from django.conf.urls import include, url
228-
from django.core.urlresolvers import clear_url_caches, reverse, NoReverseMatch
229-
import debug_toolbar
230-
try:
231-
reverse('djdt:render_panel')
232-
except NoReverseMatch:
233-
urlconf_module = import_module(settings.ROOT_URLCONF)
234-
urlconf_module.urlpatterns = [
235-
url(r'^__debug__/', include(debug_toolbar.urls)),
236-
] + urlconf_module.urlpatterns
237-
clear_url_caches()
238-
239-
240-
def patch_all():
241-
patch_internal_ips()
242-
patch_middleware_classes()
243-
patch_root_urlconf()

docs/changes.rst

+8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ Change log
44
1.6 (upcoming)
55
--------------
66

7+
Removed features
8+
~~~~~~~~~~~~~~~~
9+
10+
* Support for automatic setup has been removed as it was frequently
11+
problematic. Installation now requires explicit setup. The
12+
``DEBUG_TOOLBAR_PATCH_SETTINGS`` setting has also been removed as it is now
13+
unused. See the :doc:`installation documentation <installation>` for details.
14+
715
Bugfixes
816
~~~~~~~~
917

docs/configuration.rst

-7
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,6 @@ settings module to customize its behavior.
1212
it'll prevent you from taking advantage of better defaults that may be
1313
introduced in future releases.
1414

15-
DEBUG_TOOLBAR_PATCH_SETTINGS
16-
----------------------------
17-
18-
This setting defines whether the toolbar will attempt to automatically adjust
19-
your project's settings, as described in the :doc:`installation instructions
20-
<installation>`. By default it has the same value as your ``DEBUG`` setting.
21-
2215
DEBUG_TOOLBAR_PANELS
2316
--------------------
2417

docs/installation.rst

+17-60
Original file line numberDiff line numberDiff line change
@@ -37,48 +37,8 @@ Make sure that ``'django.contrib.staticfiles'`` is `set up properly
3737
If you're upgrading from a previous version, you should review the
3838
:doc:`change log <changes>` and look for specific upgrade instructions.
3939

40-
Automatic setup
41-
---------------
42-
43-
If you just add the Debug Toolbar to the ``INSTALLED_APPS`` setting as shown
44-
above, when the ``DEBUG`` setting is ``True``, the Debug Toolbar will attempt
45-
to patch your settings to configure itself automatically.
46-
47-
.. warning::
48-
49-
The automatic setup is known to interfere with the start-up sequence of
50-
some projects and to prevent them from loading or functioning properly.
51-
52-
**The explicit setup described below is recommended for all but the most
53-
trivial projects. The automatic setup is kept for backwards-compatibility.**
54-
55-
.. note::
56-
57-
The automatic setup imports your project's URLconf in order to add the
58-
Debug Toolbar's URLs. This is likely to trigger circular imports, for
59-
instance when the URLconf imports views that import models, a pattern
60-
found in almost every Django project.
61-
62-
If the development server crashes with a long stack trace after hitting an
63-
:exc:`ImportError`, an :exc:`~django.apps.exceptions.AppRegistryNotReady`
64-
or an :exc:`~django.core.exceptions.ImproperlyConfigured` exception, use
65-
the explicit setup described below.
66-
67-
When the automatic setup is used, the Debug Toolbar is not compatible with
68-
:class:`~django.middleware.gzip.GZipMiddleware`. Please disable that
69-
middleware during development or use the explicit setup to allow the
70-
toolbar to function properly.
71-
72-
Explicit setup
73-
--------------
74-
75-
This is the recommended way to configure the Debug Toolbar. First, disable the
76-
automatic setup by adding this line in your settings module::
77-
78-
DEBUG_TOOLBAR_PATCH_SETTINGS = False
79-
8040
URLconf
81-
~~~~~~~
41+
-------
8242

8343
Add the Debug Toolbar's URLs to your project's URLconf as follows::
8444

@@ -95,41 +55,38 @@ This example uses the ``__debug__`` prefix, but you can use any prefix that
9555
doesn't clash with your application's URLs. Note the lack of quotes around
9656
``debug_toolbar.urls``.
9757

98-
.. note::
99-
100-
The automatic setup appends the Debug Toolbar URLs to the root URLconf.
101-
10258
Middleware
103-
~~~~~~~~~~
59+
----------
10460

10561
The Debug Toolbar is mostly implemented in a middleware. Enable it in your
10662
settings module as follows::
10763

108-
MIDDLEWARE_CLASSES = [
64+
MIDDLEWARE = [
10965
# ...
11066
'debug_toolbar.middleware.DebugToolbarMiddleware',
11167
# ...
11268
]
11369

114-
The order of ``MIDDLEWARE_CLASSES`` is important. You should include the Debug
115-
Toolbar middleware as early as possible in the list. However, it must come
116-
after any other middleware that encodes the response's content, such as
117-
:class:`~django.middleware.gzip.GZipMiddleware`.
70+
Old-style middleware::
71+
72+
MIDDLEWARE_CLASSES = [
73+
# ...
74+
'debug_toolbar.middleware.DebugToolbarMiddleware',
75+
# ...
76+
]
11877

119-
.. note::
78+
.. warning::
12079

121-
The automatic setup inserts the Debug Toolbar middleware at the beginning
122-
of ``MIDDLEWARE_CLASSES``, unless it's already included.
80+
The order of ``MIDDLEWARE`` and ``MIDDLEWARE_CLASSES`` is important. You
81+
should include the Debug Toolbar middleware as early as possible in the
82+
list. However, it must come after any other middleware that encodes the
83+
response's content, such as
84+
:class:`~django.middleware.gzip.GZipMiddleware`.
12385

12486
Internal IPs
125-
~~~~~~~~~~~~
87+
------------
12688

12789
The Debug Toolbar is shown only if your IP is listed in the ``INTERNAL_IPS``
12890
setting. (You can change this logic with the ``SHOW_TOOLBAR_CALLBACK``
12991
option.) For local development, you should add ``'127.0.0.1'`` to
13092
``INTERNAL_IPS``.
131-
132-
.. note::
133-
134-
The automatic setup sets ``INTERNAL_IPS`` to ``'127.0.0.1'`` and
135-
``'::1'``, unless it's already set to a non-empty value.

example/settings.py

+16-6
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,30 @@
1111

1212
DEBUG = True
1313

14+
INTERNAL_IPS = ['127.0.0.1', '::1']
1415

1516
# Application definition
1617

17-
INSTALLED_APPS = (
18+
INSTALLED_APPS = [
1819
'django.contrib.admin',
1920
'django.contrib.auth',
2021
'django.contrib.contenttypes',
2122
'django.contrib.sessions',
2223
'django.contrib.messages',
2324
'django.contrib.staticfiles',
2425
'debug_toolbar',
25-
)
26+
]
2627

27-
MIDDLEWARE_CLASSES = (
28-
'django.middleware.common.CommonMiddleware',
28+
MIDDLEWARE = [
29+
'debug_toolbar.middleware.DebugToolbarMiddleware',
30+
'django.middleware.security.SecurityMiddleware',
2931
'django.contrib.sessions.middleware.SessionMiddleware',
32+
'django.middleware.common.CommonMiddleware',
33+
'django.middleware.csrf.CsrfViewMiddleware',
3034
'django.contrib.auth.middleware.AuthenticationMiddleware',
3135
'django.contrib.messages.middleware.MessageMiddleware',
32-
'django.middleware.csrf.CsrfViewMiddleware',
33-
)
36+
'django.middleware.clickjacking.XFrameOptionsMiddleware',
37+
]
3438

3539
ROOT_URLCONF = 'example.urls'
3640

@@ -43,6 +47,12 @@
4347
'DIRS': [os.path.join(BASE_DIR, 'example', 'templates')],
4448
'OPTIONS': {
4549
'debug': True,
50+
'context_processors': [
51+
'django.template.context_processors.debug',
52+
'django.template.context_processors.request',
53+
'django.contrib.auth.context_processors.auth',
54+
'django.contrib.messages.context_processors.messages',
55+
],
4656
},
4757
},
4858
]

example/urls.py

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from django.conf import settings
12
from django.conf.urls import include, url
23
from django.contrib import admin
34
from django.views.generic import TemplateView
@@ -9,3 +10,9 @@
910
url(r'^prototype/$', TemplateView.as_view(template_name='prototype/index.html')),
1011
url(r'^admin/', include(admin.site.urls)),
1112
]
13+
14+
if settings.DEBUG:
15+
import debug_toolbar
16+
urlpatterns += [
17+
url(r'^__debug__/', include(debug_toolbar.urls)),
18+
]

0 commit comments

Comments
 (0)