summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Apolloner <florian@apolloner.eu>2015-11-07 16:12:37 +0100
committerTim Graham <timograham@gmail.com>2016-05-17 07:22:22 -0400
commit9baf692a58de78dba13aa582098781675367c329 (patch)
tree1926555441d0c3b13185782dce193b839d616a4a
parent05c888ffb843ba3eff06cd07b3cef5bbb513a54f (diff)
Fixed #26601 -- Improved middleware per DEP 0005.
Thanks Tim Graham for polishing the patch, updating the tests, and writing documentation. Thanks Carl Meyer for shepherding the DEP.
-rw-r--r--django/conf/global_settings.py8
-rw-r--r--django/conf/project_template/project_name/settings.py-tpl2
-rw-r--r--django/contrib/admin/tests.py7
-rw-r--r--django/contrib/admindocs/middleware.py10
-rw-r--r--django/contrib/auth/middleware.py14
-rw-r--r--django/contrib/flatpages/forms.py5
-rw-r--r--django/contrib/flatpages/middleware.py13
-rw-r--r--django/contrib/messages/middleware.py3
-rw-r--r--django/contrib/messages/storage/session.py3
-rw-r--r--django/contrib/redirects/middleware.py10
-rw-r--r--django/contrib/sessions/middleware.py6
-rw-r--r--django/core/checks/security/base.py19
-rw-r--r--django/core/checks/security/csrf.py16
-rw-r--r--django/core/checks/security/sessions.py13
-rw-r--r--django/core/checks/utils.py10
-rw-r--r--django/core/handlers/base.py75
-rw-r--r--django/middleware/cache.py24
-rw-r--r--django/middleware/clickjacking.py3
-rw-r--r--django/middleware/common.py5
-rw-r--r--django/middleware/csrf.py3
-rw-r--r--django/middleware/gzip.py3
-rw-r--r--django/middleware/http.py3
-rw-r--r--django/middleware/locale.py14
-rw-r--r--django/middleware/security.py6
-rw-r--r--django/test/client.py2
-rw-r--r--django/utils/deprecation.py22
-rw-r--r--django/views/debug.py6
-rw-r--r--docs/howto/auth-remote-user.txt4
-rw-r--r--docs/howto/error-reporting.txt4
-rw-r--r--docs/ref/applications.txt4
-rw-r--r--docs/ref/checks.txt12
-rw-r--r--docs/ref/clickjacking.txt4
-rw-r--r--docs/ref/contrib/admin/index.txt4
-rw-r--r--docs/ref/contrib/flatpages.txt5
-rw-r--r--docs/ref/contrib/messages.txt8
-rw-r--r--docs/ref/contrib/redirects.txt8
-rw-r--r--docs/ref/contrib/sites.txt4
-rw-r--r--docs/ref/csrf.txt8
-rw-r--r--docs/ref/middleware.txt30
-rw-r--r--docs/ref/request-response.txt12
-rw-r--r--docs/ref/settings.txt20
-rw-r--r--docs/ref/utils.txt4
-rw-r--r--docs/releases/1.10.txt11
-rw-r--r--docs/releases/1.5.txt3
-rw-r--r--docs/topics/auth/default.txt2
-rw-r--r--docs/topics/auth/index.txt2
-rw-r--r--docs/topics/cache.txt12
-rw-r--r--docs/topics/http/_images/middleware.graffle957
-rw-r--r--docs/topics/http/_images/middleware.svg3
-rw-r--r--docs/topics/http/middleware.txt325
-rw-r--r--docs/topics/http/sessions.txt10
-rw-r--r--docs/topics/http/urls.txt4
-rw-r--r--docs/topics/i18n/timezones.txt5
-rw-r--r--docs/topics/i18n/translation.txt12
-rw-r--r--docs/topics/testing/tools.txt6
-rw-r--r--tests/auth_tests/settings.py2
-rw-r--r--tests/auth_tests/test_context_processors.py16
-rw-r--r--tests/auth_tests/test_remote_user.py17
-rw-r--r--tests/check_framework/test_security.py129
-rw-r--r--tests/file_uploads/tests.py2
-rw-r--r--tests/flatpages_tests/test_csrf.py17
-rw-r--r--tests/flatpages_tests/test_forms.py22
-rw-r--r--tests/flatpages_tests/test_middleware.py34
-rw-r--r--tests/flatpages_tests/test_templatetags.py18
-rw-r--r--tests/flatpages_tests/test_views.py4
-rw-r--r--tests/handlers/tests.py11
-rw-r--r--tests/i18n/patterns/tests.py4
-rw-r--r--tests/i18n/tests.py8
-rw-r--r--tests/logging_tests/tests.py2
-rw-r--r--tests/messages_tests/base.py4
-rw-r--r--tests/middleware_exceptions/middleware.py4
-rw-r--r--tests/middleware_exceptions/tests.py39
-rw-r--r--tests/project_template/test_settings.py12
-rw-r--r--tests/redirects_tests/tests.py16
-rwxr-xr-xtests/runtests.py6
-rw-r--r--tests/template_tests/test_response.py57
-rw-r--r--tests/test_client/tests.py2
-rw-r--r--tests/urlpatterns_reverse/middleware.py13
-rw-r--r--tests/urlpatterns_reverse/tests.py12
-rw-r--r--tests/view_tests/tests/test_csrf.py28
-rw-r--r--tests/view_tests/tests/test_i18n.py43
81 files changed, 898 insertions, 1412 deletions
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index 1b71b1b1b8..09af2fcda4 100644
--- a/django/conf/global_settings.py
+++ b/django/conf/global_settings.py
@@ -433,14 +433,16 @@ SECURE_PROXY_SSL_HEADER = None
# MIDDLEWARE #
##############
-# List of middleware classes to use. Order is important; in the request phase,
-# this middleware classes will be applied in the order given, and in the
-# response phase the middleware will be applied in reverse order.
+# List of middleware to use. Order is important; in the request phase, these
+# middleware will be applied in the order given, and in the response
+# phase the middleware will be applied in reverse order.
MIDDLEWARE_CLASSES = [
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
]
+MIDDLEWARE = None
+
############
# SESSIONS #
############
diff --git a/django/conf/project_template/project_name/settings.py-tpl b/django/conf/project_template/project_name/settings.py-tpl
index 3ef0ab7900..7dfe186929 100644
--- a/django/conf/project_template/project_name/settings.py-tpl
+++ b/django/conf/project_template/project_name/settings.py-tpl
@@ -39,7 +39,7 @@ INSTALLED_APPS = [
'django.contrib.staticfiles',
]
-MIDDLEWARE_CLASSES = [
+MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
diff --git a/django/contrib/admin/tests.py b/django/contrib/admin/tests.py
index e569df396b..7043ed80b8 100644
--- a/django/contrib/admin/tests.py
+++ b/django/contrib/admin/tests.py
@@ -1,19 +1,18 @@
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from django.test import modify_settings
from django.test.selenium import SeleniumTestCase
+from django.utils.deprecation import MiddlewareMixin
from django.utils.translation import ugettext as _
-class CSPMiddleware(object):
+class CSPMiddleware(MiddlewareMixin):
"""The admin's JavaScript should be compatible with CSP."""
def process_response(self, request, response):
response['Content-Security-Policy'] = "default-src 'self'"
return response
-@modify_settings(
- MIDDLEWARE_CLASSES={'append': 'django.contrib.admin.tests.CSPMiddleware'},
-)
+@modify_settings(MIDDLEWARE={'append': 'django.contrib.admin.tests.CSPMiddleware'})
class AdminSeleniumTestCase(SeleniumTestCase, StaticLiveServerTestCase):
available_apps = [
diff --git a/django/contrib/admindocs/middleware.py b/django/contrib/admindocs/middleware.py
index 2e4cede0b9..4bdd4f45b5 100644
--- a/django/contrib/admindocs/middleware.py
+++ b/django/contrib/admindocs/middleware.py
@@ -1,8 +1,9 @@
from django import http
from django.conf import settings
+from django.utils.deprecation import MiddlewareMixin
-class XViewMiddleware(object):
+class XViewMiddleware(MiddlewareMixin):
"""
Adds an X-View header to internal HEAD requests -- used by the documentation system.
"""
@@ -15,8 +16,11 @@ class XViewMiddleware(object):
"""
assert hasattr(request, 'user'), (
"The XView middleware requires authentication middleware to be "
- "installed. Edit your MIDDLEWARE_CLASSES setting to insert "
- "'django.contrib.auth.middleware.AuthenticationMiddleware'.")
+ "installed. Edit your MIDDLEWARE%s setting to insert "
+ "'django.contrib.auth.middleware.AuthenticationMiddleware'." % (
+ "_CLASSES" if settings.MIDDLEWARE is None else ""
+ )
+ )
if request.method == 'HEAD' and (request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS or
(request.user.is_active and request.user.is_staff)):
response = http.HttpResponse()
diff --git a/django/contrib/auth/middleware.py b/django/contrib/auth/middleware.py
index 476729c147..8c56e645fe 100644
--- a/django/contrib/auth/middleware.py
+++ b/django/contrib/auth/middleware.py
@@ -1,7 +1,9 @@
+from django.conf import settings
from django.contrib import auth
from django.contrib.auth import load_backend
from django.contrib.auth.backends import RemoteUserBackend
from django.core.exceptions import ImproperlyConfigured
+from django.utils.deprecation import MiddlewareMixin
from django.utils.functional import SimpleLazyObject
@@ -11,18 +13,18 @@ def get_user(request):
return request._cached_user
-class AuthenticationMiddleware(object):
+class AuthenticationMiddleware(MiddlewareMixin):
def process_request(self, request):
assert hasattr(request, 'session'), (
"The Django authentication middleware requires session middleware "
- "to be installed. Edit your MIDDLEWARE_CLASSES setting to insert "
+ "to be installed. Edit your MIDDLEWARE%s setting to insert "
"'django.contrib.sessions.middleware.SessionMiddleware' before "
"'django.contrib.auth.middleware.AuthenticationMiddleware'."
- )
+ ) % ("_CLASSES" if settings.MIDDLEWARE is None else "")
request.user = SimpleLazyObject(lambda: get_user(request))
-class SessionAuthenticationMiddleware(object):
+class SessionAuthenticationMiddleware(MiddlewareMixin):
"""
Formerly, a middleware for invalidating a user's sessions that don't
correspond to the user's current session authentication hash. However, it
@@ -35,7 +37,7 @@ class SessionAuthenticationMiddleware(object):
pass
-class RemoteUserMiddleware(object):
+class RemoteUserMiddleware(MiddlewareMixin):
"""
Middleware for utilizing Web-server-provided authentication.
@@ -61,7 +63,7 @@ class RemoteUserMiddleware(object):
raise ImproperlyConfigured(
"The Django remote user auth middleware requires the"
" authentication middleware to be installed. Edit your"
- " MIDDLEWARE_CLASSES setting to insert"
+ " MIDDLEWARE setting to insert"
" 'django.contrib.auth.middleware.AuthenticationMiddleware'"
" before the RemoteUserMiddleware class.")
try:
diff --git a/django/contrib/flatpages/forms.py b/django/contrib/flatpages/forms.py
index 19f3b6309c..fbc7da04de 100644
--- a/django/contrib/flatpages/forms.py
+++ b/django/contrib/flatpages/forms.py
@@ -29,8 +29,9 @@ class FlatpageForm(forms.ModelForm):
ugettext("URL is missing a leading slash."),
code='missing_leading_slash',
)
- if (settings.APPEND_SLASH and
- 'django.middleware.common.CommonMiddleware' in settings.MIDDLEWARE_CLASSES and
+ if (settings.APPEND_SLASH and (
+ (settings.MIDDLEWARE and 'django.middleware.common.CommonMiddleware' in settings.MIDDLEWARE) or
+ 'django.middleware.common.CommonMiddleware' in settings.MIDDLEWARE_CLASSES) and
not url.endswith('/')):
raise forms.ValidationError(
ugettext("URL is missing a trailing slash."),
diff --git a/django/contrib/flatpages/middleware.py b/django/contrib/flatpages/middleware.py
index 32d881ffa4..4c6760535d 100644
--- a/django/contrib/flatpages/middleware.py
+++ b/django/contrib/flatpages/middleware.py
@@ -1,9 +1,20 @@
from django.conf import settings
from django.contrib.flatpages.views import flatpage
from django.http import Http404
+from django.middleware.exception import ExceptionMiddleware
-class FlatpageFallbackMiddleware(object):
+class FlatpageFallbackMiddleware(ExceptionMiddleware):
+
+ def __init__(self, get_response=None):
+ # This override makes get_response optional during the
+ # MIDDLEWARE_CLASSES deprecation.
+ super(FlatpageFallbackMiddleware, self).__init__(get_response)
+
+ def __call__(self, request):
+ response = super(FlatpageFallbackMiddleware, self).__call__(request)
+ return self.process_response(request, response)
+
def process_response(self, request, response):
if response.status_code != 404:
return response # No need to check for a flatpage for non-404 responses.
diff --git a/django/contrib/messages/middleware.py b/django/contrib/messages/middleware.py
index a84dc6cb11..4cdbf63c64 100644
--- a/django/contrib/messages/middleware.py
+++ b/django/contrib/messages/middleware.py
@@ -1,8 +1,9 @@
from django.conf import settings
from django.contrib.messages.storage import default_storage
+from django.utils.deprecation import MiddlewareMixin
-class MessageMiddleware(object):
+class MessageMiddleware(MiddlewareMixin):
"""
Middleware that handles temporary messages.
"""
diff --git a/django/contrib/messages/storage/session.py b/django/contrib/messages/storage/session.py
index 7903fb03c1..624de42b8c 100644
--- a/django/contrib/messages/storage/session.py
+++ b/django/contrib/messages/storage/session.py
@@ -1,5 +1,6 @@
import json
+from django.conf import settings
from django.contrib.messages.storage.base import BaseStorage
from django.contrib.messages.storage.cookie import (
MessageDecoder, MessageEncoder,
@@ -17,7 +18,7 @@ class SessionStorage(BaseStorage):
assert hasattr(request, 'session'), "The session-based temporary "\
"message storage requires session middleware to be installed, "\
"and come before the message middleware in the "\
- "MIDDLEWARE_CLASSES list."
+ "MIDDLEWARE%s list." % ("_CLASSES" if settings.MIDDLEWARE is None else "")
super(SessionStorage, self).__init__(request, *args, **kwargs)
def _get(self, *args, **kwargs):
diff --git a/django/contrib/redirects/middleware.py b/django/contrib/redirects/middleware.py
index dc8d94bc96..e3ee982a8b 100644
--- a/django/contrib/redirects/middleware.py
+++ b/django/contrib/redirects/middleware.py
@@ -6,20 +6,26 @@ from django.conf import settings
from django.contrib.redirects.models import Redirect
from django.contrib.sites.shortcuts import get_current_site
from django.core.exceptions import ImproperlyConfigured
+from django.middleware.exception import ExceptionMiddleware
-class RedirectFallbackMiddleware(object):
+class RedirectFallbackMiddleware(ExceptionMiddleware):
# Defined as class-level attributes to be subclassing-friendly.
response_gone_class = http.HttpResponseGone
response_redirect_class = http.HttpResponsePermanentRedirect
- def __init__(self):
+ def __init__(self, get_response=None):
if not apps.is_installed('django.contrib.sites'):
raise ImproperlyConfigured(
"You cannot use RedirectFallbackMiddleware when "
"django.contrib.sites is not installed."
)
+ super(RedirectFallbackMiddleware, self).__init__(get_response)
+
+ def __call__(self, request):
+ response = super(RedirectFallbackMiddleware, self).__call__(request)
+ return self.process_response(request, response)
def process_response(self, request, response):
# No need to check for a redirect for non-404 responses.
diff --git a/django/contrib/sessions/middleware.py b/django/contrib/sessions/middleware.py
index 73ffe5a2a2..4871b48075 100644
--- a/django/contrib/sessions/middleware.py
+++ b/django/contrib/sessions/middleware.py
@@ -5,11 +5,13 @@ from django.conf import settings
from django.contrib.sessions.backends.base import UpdateError
from django.shortcuts import redirect
from django.utils.cache import patch_vary_headers
+from django.utils.deprecation import MiddlewareMixin
from django.utils.http import cookie_date
-class SessionMiddleware(object):
- def __init__(self):
+class SessionMiddleware(MiddlewareMixin):
+ def __init__(self, get_response=None):
+ self.get_response = get_response
engine = import_module(settings.SESSION_ENGINE)
self.SessionStore = engine.SessionStore
diff --git a/django/core/checks/security/base.py b/django/core/checks/security/base.py
index eacbb90843..eee7f854c8 100644
--- a/django/core/checks/security/base.py
+++ b/django/core/checks/security/base.py
@@ -1,13 +1,14 @@
from django.conf import settings
from .. import Tags, Warning, register
+from ..utils import patch_middleware_message
SECRET_KEY_MIN_LENGTH = 50
SECRET_KEY_MIN_UNIQUE_CHARACTERS = 5
W001 = Warning(
"You do not have 'django.middleware.security.SecurityMiddleware' "
- "in your MIDDLEWARE_CLASSES so the SECURE_HSTS_SECONDS, "
+ "in your MIDDLEWARE so the SECURE_HSTS_SECONDS, "
"SECURE_CONTENT_TYPE_NOSNIFF, "
"SECURE_BROWSER_XSS_FILTER, and SECURE_SSL_REDIRECT settings "
"will have no effect.",
@@ -17,7 +18,7 @@ W001 = Warning(
W002 = Warning(
"You do not have "
"'django.middleware.clickjacking.XFrameOptionsMiddleware' in your "
- "MIDDLEWARE_CLASSES, so your pages will not be served with an "
+ "MIDDLEWARE, so your pages will not be served with an "
"'x-frame-options' header. Unless there is a good reason for your "
"site to be served in a frame, you should consider enabling this "
"header to help prevent clickjacking attacks.",
@@ -88,7 +89,7 @@ W018 = Warning(
W019 = Warning(
"You have "
"'django.middleware.clickjacking.XFrameOptionsMiddleware' in your "
- "MIDDLEWARE_CLASSES, but X_FRAME_OPTIONS is not set to 'DENY'. "
+ "MIDDLEWARE, but X_FRAME_OPTIONS is not set to 'DENY'. "
"The default is 'SAMEORIGIN', but unless there is a good reason for "
"your site to serve other parts of itself in a frame, you should "
"change it to 'DENY'.",
@@ -102,23 +103,25 @@ W020 = Warning(
def _security_middleware():
- return "django.middleware.security.SecurityMiddleware" in settings.MIDDLEWARE_CLASSES
+ return ("django.middleware.security.SecurityMiddleware" in settings.MIDDLEWARE_CLASSES or
+ settings.MIDDLEWARE and "django.middleware.security.SecurityMiddleware" in settings.MIDDLEWARE)
def _xframe_middleware():
- return "django.middleware.clickjacking.XFrameOptionsMiddleware" in settings.MIDDLEWARE_CLASSES
+ return ("django.middleware.clickjacking.XFrameOptionsMiddleware" in settings.MIDDLEWARE_CLASSES or
+ settings.MIDDLEWARE and "django.middleware.clickjacking.XFrameOptionsMiddleware" in settings.MIDDLEWARE)
@register(Tags.security, deploy=True)
def check_security_middleware(app_configs, **kwargs):
passed_check = _security_middleware()
- return [] if passed_check else [W001]
+ return [] if passed_check else [patch_middleware_message(W001)]
@register(Tags.security, deploy=True)
def check_xframe_options_middleware(app_configs, **kwargs):
passed_check = _xframe_middleware()
- return [] if passed_check else [W002]
+ return [] if passed_check else [patch_middleware_message(W002)]
@register(Tags.security, deploy=True)
@@ -186,7 +189,7 @@ def check_xframe_deny(app_configs, **kwargs):
not _xframe_middleware() or
settings.X_FRAME_OPTIONS == 'DENY'
)
- return [] if passed_check else [W019]
+ return [] if passed_check else [patch_middleware_message(W019)]
@register(Tags.security, deploy=True)
diff --git a/django/core/checks/security/csrf.py b/django/core/checks/security/csrf.py
index 3effbc4498..b90308a016 100644
--- a/django/core/checks/security/csrf.py
+++ b/django/core/checks/security/csrf.py
@@ -1,19 +1,20 @@
from django.conf import settings
from .. import Tags, Warning, register
+from ..utils import patch_middleware_message
W003 = Warning(
"You don't appear to be using Django's built-in "
"cross-site request forgery protection via the middleware "
"('django.middleware.csrf.CsrfViewMiddleware' is not in your "
- "MIDDLEWARE_CLASSES). Enabling the middleware is the safest approach "
+ "MIDDLEWARE). Enabling the middleware is the safest approach "
"to ensure you don't leave any holes.",
id='security.W003',
)
W016 = Warning(
"You have 'django.middleware.csrf.CsrfViewMiddleware' in your "
- "MIDDLEWARE_CLASSES, but you have not set CSRF_COOKIE_SECURE to True. "
+ "MIDDLEWARE, but you have not set CSRF_COOKIE_SECURE to True. "
"Using a secure-only CSRF cookie makes it more difficult for network "
"traffic sniffers to steal the CSRF token.",
id='security.W016',
@@ -21,7 +22,7 @@ W016 = Warning(
W017 = Warning(
"You have 'django.middleware.csrf.CsrfViewMiddleware' in your "
- "MIDDLEWARE_CLASSES, but you have not set CSRF_COOKIE_HTTPONLY to True. "
+ "MIDDLEWARE, but you have not set CSRF_COOKIE_HTTPONLY to True. "
"Using an HttpOnly CSRF cookie makes it more difficult for cross-site "
"scripting attacks to steal the CSRF token.",
id='security.W017',
@@ -29,13 +30,14 @@ W017 = Warning(
def _csrf_middleware():
- return "django.middleware.csrf.CsrfViewMiddleware" in settings.MIDDLEWARE_CLASSES
+ return ("django.middleware.csrf.CsrfViewMiddleware" in settings.MIDDLEWARE_CLASSES or
+ settings.MIDDLEWARE and "django.middleware.csrf.CsrfViewMiddleware" in settings.MIDDLEWARE)
@register(Tags.security, deploy=True)
def check_csrf_middleware(app_configs, **kwargs):
passed_check = _csrf_middleware()
- return [] if passed_check else [W003]
+ return [] if passed_check else [patch_middleware_message(W003)]
@register(Tags.security, deploy=True)
@@ -44,7 +46,7 @@ def check_csrf_cookie_secure(app_configs, **kwargs):
not _csrf_middleware() or
settings.CSRF_COOKIE_SECURE
)
- return [] if passed_check else [W016]
+ return [] if passed_check else [patch_middleware_message(W016)]
@register(Tags.security, deploy=True)
@@ -53,4 +55,4 @@ def check_csrf_cookie_httponly(app_configs, **kwargs):
not _csrf_middleware() or
settings.CSRF_COOKIE_HTTPONLY
)
- return [] if passed_check else [W017]
+ return [] if passed_check else [patch_middleware_message(W017)]
diff --git a/django/core/checks/security/sessions.py b/django/core/checks/security/sessions.py
index 7e857d74d8..5fae4ed4d9 100644
--- a/django/core/checks/security/sessions.py
+++ b/django/core/checks/security/sessions.py
@@ -1,6 +1,7 @@
from django.conf import settings
from .. import Tags, Warning, register
+from ..utils import patch_middleware_message
def add_session_cookie_message(message):
@@ -20,7 +21,7 @@ W010 = Warning(
W011 = Warning(
add_session_cookie_message(
"You have 'django.contrib.sessions.middleware.SessionMiddleware' "
- "in your MIDDLEWARE_CLASSES, but you have not set "
+ "in your MIDDLEWARE, but you have not set "
"SESSION_COOKIE_SECURE to True."
),
id='security.W011',
@@ -50,7 +51,7 @@ W013 = Warning(
W014 = Warning(
add_httponly_message(
"You have 'django.contrib.sessions.middleware.SessionMiddleware' "
- "in your MIDDLEWARE_CLASSES, but you have not set "
+ "in your MIDDLEWARE, but you have not set "
"SESSION_COOKIE_HTTPONLY to True."
),
id='security.W014',
@@ -69,7 +70,7 @@ def check_session_cookie_secure(app_configs, **kwargs):
if _session_app():
errors.append(W010)
if _session_middleware():
- errors.append(W011)
+ errors.append(patch_middleware_message(W011))
if len(errors) > 1:
errors = [W012]
return errors
@@ -82,15 +83,15 @@ def check_session_cookie_httponly(app_configs, **kwargs):
if _session_app():
errors.append(W013)
if _session_middleware():
- errors.append(W014)
+ errors.append(patch_middleware_message(W014))
if len(errors) > 1:
errors = [W015]
return errors
def _session_middleware():
- return ("django.contrib.sessions.middleware.SessionMiddleware" in
- settings.MIDDLEWARE_CLASSES)
+ return ("django.contrib.sessions.middleware.SessionMiddleware" in settings.MIDDLEWARE_CLASSES or
+ settings.MIDDLEWARE and "django.contrib.sessions.middleware.SessionMiddleware" in settings.MIDDLEWARE)
def _session_app():
diff --git a/django/core/checks/utils.py b/django/core/checks/utils.py
new file mode 100644
index 0000000000..995d8432c9
--- /dev/null
+++ b/django/core/checks/utils.py
@@ -0,0 +1,10 @@
+import copy
+
+from django.conf import settings
+
+
+def patch_middleware_message(error):
+ if settings.MIDDLEWARE is None:
+ error = copy.copy(error)
+ error.msg = error.msg.replace('MIDDLEWARE', 'MIDDLEWARE_CLASSES')
+ return error
diff --git a/django/core/handlers/base.py b/django/core/handlers/base.py
index 65cb59357c..b206c70b05 100644
--- a/django/core/handlers/base.py
+++ b/django/core/handlers/base.py
@@ -7,7 +7,7 @@ import warnings
from django.conf import settings
from django.core import signals
-from django.core.exceptions import MiddlewareNotUsed
+from django.core.exceptions import ImproperlyConfigured, MiddlewareNotUsed
from django.db import connections, transaction
from django.middleware.exception import ExceptionMiddleware
from django.urls import get_resolver, get_urlconf, set_urlconf
@@ -31,7 +31,8 @@ class BaseHandler(object):
def load_middleware(self):
"""
- Populate middleware lists from settings.MIDDLEWARE_CLASSES.
+ Populate middleware lists from settings.MIDDLEWARE (or the deprecated
+ MIDDLEWARE_CLASSES).
Must be called after the environment is fixed (see __call__ in subclasses).
"""
@@ -41,29 +42,55 @@ class BaseHandler(object):
self._response_middleware = []
self._exception_middleware = []
- handler = self._legacy_get_response
- for middleware_path in settings.MIDDLEWARE_CLASSES:
- mw_class = import_string(middleware_path)
- try:
- mw_instance = mw_class()
- except MiddlewareNotUsed as exc:
- if settings.DEBUG:
- if six.text_type(exc):
- logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
- else:
- logger.debug('MiddlewareNotUsed: %r', middleware_path)
- continue
+ if settings.MIDDLEWARE is None:
+ handler = self._legacy_get_response
+ for middleware_path in settings.MIDDLEWARE_CLASSES:
+ mw_class = import_string(middleware_path)
+ try:
+ mw_instance = mw_class()
+ except MiddlewareNotUsed as exc:
+ if settings.DEBUG:
+ if six.text_type(exc):
+ logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
+ else:
+ logger.debug('MiddlewareNotUsed: %r', middleware_path)
+ continue
+
+ if hasattr(mw_instance, 'process_request'):
+ self._request_middleware.append(mw_instance.process_request)
+ if hasattr(mw_instance, 'process_view'):
+ self._view_middleware.append(mw_instance.process_view)
+ if hasattr(mw_instance, 'process_template_response'):
+ self._template_response_middleware.insert(0, mw_instance.process_template_response)
+ if hasattr(mw_instance, 'process_response'):
+ self._response_middleware.insert(0, mw_instance.process_response)
+ if hasattr(mw_instance, 'process_exception'):
+ self._exception_middleware.insert(0, mw_instance.process_exception)
+ else:
+ handler = self._get_response
+ for middleware_path in reversed(settings.MIDDLEWARE):
+ middleware = import_string(middleware_path)
+ try:
+ mw_instance = middleware(handler)
+ except MiddlewareNotUsed as exc:
+ if settings.DEBUG:
+ if six.text_type(exc):
+ logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
+ else:
+ logger.debug('MiddlewareNotUsed: %r', middleware_path)
+ continue
+
+ if mw_instance is None:
+ raise ImproperlyConfigured(
+ 'Middleware factory %s returned None.' % middleware_path
+ )
+
+ if hasattr(mw_instance, 'process_view'):
+ self._view_middleware.insert(0, mw_instance.process_view)
+ if hasattr(mw_instance, 'process_template_response'):
+ self._template_response_middleware.append(mw_instance.process_template_response)
- if hasattr(mw_instance, 'process_request'):
- self._request_middleware.append(mw_instance.process_request)
- if hasattr(mw_instance, 'process_view'):
- self._view_middleware.append(mw_instance.process_view)
- if hasattr(mw_instance, 'process_template_response'):
- self._template_response_middleware.insert(0, mw_instance.process_template_response)
- if hasattr(mw_instance, 'process_response'):
- self._response_middleware.insert(0, mw_instance.process_response)
- if hasattr(mw_instance, 'process_exception'):
- self._exception_middleware.insert(0, mw_instance.process_exception)
+ handler = mw_instance
handler = ExceptionMiddleware(handler, self)
diff --git a/django/middleware/cache.py b/django/middleware/cache.py
index 11a65cd928..8ee3f514e8 100644
--- a/django/middleware/cache.py
+++ b/django/middleware/cache.py
@@ -4,7 +4,7 @@ URL. The canonical way to enable cache middleware is to set
``UpdateCacheMiddleware`` as your first piece of middleware, and
``FetchFromCacheMiddleware`` as the last::
- MIDDLEWARE_CLASSES = [
+ MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
...
'django.middleware.cache.FetchFromCacheMiddleware'
@@ -49,22 +49,24 @@ from django.utils.cache import (
get_cache_key, get_max_age, has_vary_header, learn_cache_key,
patch_response_headers,
)
+from django.utils.deprecation import MiddlewareMixin
-class UpdateCacheMiddleware(object):
+class UpdateCacheMiddleware(MiddlewareMixin):
"""
Response-phase cache middleware that updates the cache if the response is
cacheable.
Must be used as part of the two-part update/fetch cache middleware.
- UpdateCacheMiddleware must be the first piece of middleware in
- MIDDLEWARE_CLASSES so that it'll get called last during the response phase.
+ UpdateCacheMiddleware must be the first piece of middleware in MIDDLEWARE
+ so that it'll get called last during the response phase.
"""
- def __init__(self):
+ def __init__(self, get_response=None):
self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS
self.cache = caches[self.cache_alias]
+ self.get_response = get_response
def _should_update_cache(self, request, response):
return hasattr(request, '_cache_update_cache') and request._cache_update_cache
@@ -104,18 +106,19 @@ class UpdateCacheMiddleware(object):
return response
-class FetchFromCacheMiddleware(object):
+class FetchFromCacheMiddleware(MiddlewareMixin):
"""
Request-phase cache middleware that fetches a page from the cache.
Must be used as part of the two-part update/fetch cache middleware.
- FetchFromCacheMiddleware must be the last piece of middleware in
- MIDDLEWARE_CLASSES so that it'll get called last during the request phase.
+ FetchFromCacheMiddleware must be the last piece of middleware in MIDDLEWARE
+ so that it'll get called last during the request phase.
"""
- def __init__(self):
+ def __init__(self, get_response=None):
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS
self.cache = caches[self.cache_alias]
+ self.get_response = get_response
def process_request(self, request):
"""
@@ -153,7 +156,8 @@ class CacheMiddleware(UpdateCacheMiddleware, FetchFromCacheMiddleware):
Also used as the hook point for the cache decorator, which is generated
using the decorator-from-middleware utility.
"""
- def __init__(self, cache_timeout=None, **kwargs):
+ def __init__(self, get_response=None, cache_timeout=None, **kwargs):
+ self.get_response = get_response
# We need to differentiate between "provided, but using default value",
# and "not provided". If the value is provided using a default, then
# we fall back to system defaults. If it is not provided at all,
diff --git a/django/middleware/clickjacking.py b/django/middleware/clickjacking.py
index acd0705703..8659646c61 100644
--- a/django/middleware/clickjacking.py
+++ b/django/middleware/clickjacking.py
@@ -6,9 +6,10 @@ malicious site loading resources from your site in a hidden frame.
"""
from django.conf import settings
+from django.utils.deprecation import MiddlewareMixin
-class XFrameOptionsMiddleware(object):
+class XFrameOptionsMiddleware(MiddlewareMixin):
"""
Middleware that sets the X-Frame-Options HTTP header in HTTP responses.
diff --git a/django/middleware/common.py b/django/middleware/common.py
index b7db74a018..4cec6f0e41 100644
--- a/django/middleware/common.py
+++ b/django/middleware/common.py
@@ -7,6 +7,7 @@ from django.core.exceptions import PermissionDenied
from django.core.mail import mail_managers
from django.urls import is_valid_path
from django.utils.cache import get_conditional_response, set_response_etag
+from django.utils.deprecation import MiddlewareMixin
from django.utils.encoding import force_text
from django.utils.http import unquote_etag
from django.utils.six.moves.urllib.parse import urlparse
@@ -14,7 +15,7 @@ from django.utils.six.moves.urllib.parse import urlparse
logger = logging.getLogger('django.request')
-class CommonMiddleware(object):
+class CommonMiddleware(MiddlewareMixin):
"""
"Common" middleware for taking care of some basic operations:
@@ -129,7 +130,7 @@ class CommonMiddleware(object):
return response
-class BrokenLinkEmailsMiddleware(object):
+class BrokenLinkEmailsMiddleware(MiddlewareMixin):
def process_response(self, request, response):
"""
diff --git a/django/middleware/csrf.py b/django/middleware/csrf.py
index f2d6a49708..ba9f63ec3d 100644
--- a/django/middleware/csrf.py
+++ b/django/middleware/csrf.py
@@ -13,6 +13,7 @@ from django.conf import settings
from django.urls import get_callable
from django.utils.cache import patch_vary_headers
from django.utils.crypto import constant_time_compare, get_random_string
+from django.utils.deprecation import MiddlewareMixin
from django.utils.encoding import force_text
from django.utils.http import is_same_domain
from django.utils.six.moves.urllib.parse import urlparse
@@ -78,7 +79,7 @@ def _sanitize_token(token):
return token
-class CsrfViewMiddleware(object):
+class CsrfViewMiddleware(MiddlewareMixin):
"""
Middleware that requires a present and correct csrfmiddlewaretoken
for POST requests that have a CSRF cookie, and sets an outgoing
diff --git a/django/middleware/gzip.py b/django/middleware/gzip.py
index e772cb326d..642e3188d3 100644
--- a/django/middleware/gzip.py
+++ b/django/middleware/gzip.py
@@ -1,12 +1,13 @@
import re
from django.utils.cache import patch_vary_headers
+from django.utils.deprecation import MiddlewareMixin
from django.utils.text import compress_sequence, compress_string
re_accepts_gzip = re.compile(r'\bgzip\b')
-class GZipMiddleware(object):
+class GZipMiddleware(MiddlewareMixin):
"""
This middleware compresses content if the browser allows gzip compression.
It sets the Vary header accordingly, so that caches will base their storage
diff --git a/django/middleware/http.py b/django/middleware/http.py
index 7912200634..a3030463c4 100644
--- a/django/middleware/http.py
+++ b/django/middleware/http.py
@@ -1,8 +1,9 @@
from django.utils.cache import get_conditional_response
+from django.utils.deprecation import MiddlewareMixin
from django.utils.http import http_date, parse_http_date_safe, unquote_etag
-class ConditionalGetMiddleware(object):
+class ConditionalGetMiddleware(MiddlewareMixin):
"""
Handles conditional GET operations. If the response has an ETag or
Last-Modified header, and the request has If-None-Match or
diff --git a/django/middleware/locale.py b/django/middleware/locale.py
index f8b16b8475..1a95dbc8b2 100644
--- a/django/middleware/locale.py
+++ b/django/middleware/locale.py
@@ -3,12 +3,13 @@
from django.conf import settings
from django.conf.urls.i18n import is_language_prefix_patterns_used
from django.http import HttpResponseRedirect
+from django.middleware.exception import ExceptionMiddleware
from django.urls import get_script_prefix, is_valid_path
from django.utils import translation
from django.utils.cache import patch_vary_headers
-class LocaleMiddleware(object):
+class LocaleMiddleware(ExceptionMiddleware):
"""
This is a very simple middleware that parses a request
and decides what translation object to install in the current
@@ -18,6 +19,17 @@ class LocaleMiddleware(object):
"""
response_redirect_class = HttpResponseRedirect
+ def __init__(self, get_response=None):
+ # This override makes get_response optional during the
+ # MIDDLEWARE_CLASSES deprecation.
+ super(LocaleMiddleware, self).__init__(get_response)
+
+ def __call__(self, request):
+ response = self.process_request(request)
+ if not response:
+ response = super(LocaleMiddleware, self).__call__(request)
+ return self.process_response(request, response)
+
def process_request(self, request):
urlconf = getattr(request, 'urlconf', settings.ROOT_URLCONF)
i18n_patterns_used, prefixed_default_language = is_language_prefix_patterns_used(urlconf)
diff --git a/django/middleware/security.py b/django/middleware/security.py
index 46afb68f57..02a59ad6e4 100644
--- a/django/middleware/security.py
+++ b/django/middleware/security.py
@@ -2,10 +2,11 @@ import re
from django.conf import settings
from django.http import HttpResponsePermanentRedirect
+from django.utils.deprecation import MiddlewareMixin
-class SecurityMiddleware(object):
- def __init__(self):
+class SecurityMiddleware(MiddlewareMixin):
+ def __init__(self, get_response=None):
self.sts_seconds = settings.SECURE_HSTS_SECONDS
self.sts_include_subdomains = settings.SECURE_HSTS_INCLUDE_SUBDOMAINS
self.content_type_nosniff = settings.SECURE_CONTENT_TYPE_NOSNIFF
@@ -13,6 +14,7 @@ class SecurityMiddleware(object):
self.redirect = settings.SECURE_SSL_REDIRECT
self.redirect_host = settings.SECURE_SSL_HOST
self.redirect_exempt = [re.compile(r) for r in settings.SECURE_REDIRECT_EXEMPT]
+ self.get_response = get_response
def process_request(self, request):
path = request.path.lstrip("/")
diff --git a/django/test/client.py b/django/test/client.py
index e6a3650701..dc813716d6 100644
--- a/django/test/client.py
+++ b/django/test/client.py
@@ -125,7 +125,7 @@ class ClientHandler(BaseHandler):
def __call__(self, environ):
# Set up middleware if needed. We couldn't do this earlier, because
# settings weren't available.
- if self._request_middleware is None:
+ if self._middleware_chain is None:
self.load_middleware()
request_started.disconnect(close_old_connections)
diff --git a/django/utils/deprecation.py b/django/utils/deprecation.py
index 70216e8c5b..7627426080 100644
--- a/django/utils/deprecation.py
+++ b/django/utils/deprecation.py
@@ -109,3 +109,25 @@ class CallableBool:
CallableFalse = CallableBool(False)
CallableTrue = CallableBool(True)
+
+
+class MiddlewareMixin(object):
+ def __init__(self, get_response=None):
+ self.get_response = get_response
+ super(MiddlewareMixin, self).__init__()
+
+ def __call__(self, request):
+ response = None
+ if hasattr(self, 'process_request'):
+ response = self.process_request(request)
+ if not response:
+ try:
+ response = self.get_response(request)
+ except Exception as e:
+ if hasattr(self, 'process_exception'):
+ return self.process_exception(request, e)
+ else:
+ raise
+ if hasattr(self, 'process_response'):
+ response = self.process_response(request, response)
+ return response
diff --git a/django/views/debug.py b/django/views/debug.py
index 73fedce68d..56329325d3 100644
--- a/django/views/debug.py
+++ b/django/views/debug.py
@@ -852,7 +852,8 @@ Python Version: {{ sys_version_info }}
Installed Applications:
{{ settings.INSTALLED_APPS|pprint }}
Installed Middleware:
-{{ settings.MIDDLEWARE_CLASSES|pprint }}
+{% if settings.MIDDLEWARE is not None %}{{ settings.MIDDLEWARE|pprint }}"""
+"""{% else %}{{ settings.MIDDLEWARE_CLASSES|pprint }}{% endif %}
{% if template_does_not_exist %}Template loader postmortem
{% if postmortem %}Django tried loading these templates, in this order:
@@ -1059,7 +1060,8 @@ Server time: {{server_time|date:"r"}}
Installed Applications:
{{ settings.INSTALLED_APPS|pprint }}
Installed Middleware:
-{{ settings.MIDDLEWARE_CLASSES|pprint }}
+{% if settings.MIDDLEWARE is not None %}{{ settings.MIDDLEWARE|pprint }}"""
+"""{% else %}{{ settings.MIDDLEWARE_CLASSES|pprint }}{% endif %}
{% if template_does_not_exist %}Template loader postmortem
{% if postmortem %}Django tried loading these templates, in this order:
{% for entry in postmortem %}
diff --git a/docs/howto/auth-remote-user.txt b/docs/howto/auth-remote-user.txt
index 1680baa92b..5bfe210458 100644
--- a/docs/howto/auth-remote-user.txt
+++ b/docs/howto/auth-remote-user.txt
@@ -29,10 +29,10 @@ Configuration
First, you must add the
:class:`django.contrib.auth.middleware.RemoteUserMiddleware` to the
-:setting:`MIDDLEWARE_CLASSES` setting **after** the
+:setting:`MIDDLEWARE` setting **after** the
:class:`django.contrib.auth.middleware.AuthenticationMiddleware`::
- MIDDLEWARE_CLASSES = [
+ MIDDLEWARE = [
'...',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware',
diff --git a/docs/howto/error-reporting.txt b/docs/howto/error-reporting.txt
index d07404a1e9..7a51338539 100644
--- a/docs/howto/error-reporting.txt
+++ b/docs/howto/error-reporting.txt
@@ -57,7 +57,7 @@ not found" errors). Django sends emails about 404 errors when:
* :setting:`DEBUG` is ``False``;
-* Your :setting:`MIDDLEWARE_CLASSES` setting includes
+* Your :setting:`MIDDLEWARE` setting includes
:class:`django.middleware.common.BrokenLinkEmailsMiddleware`.
If those conditions are met, Django will email the users listed in the
@@ -78,7 +78,7 @@ behavior is from broken Web bots too.
before other middleware that intercepts 404 errors, such as
:class:`~django.middleware.locale.LocaleMiddleware` or
:class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware`.
- Put it towards the top of your :setting:`MIDDLEWARE_CLASSES` setting.
+ Put it towards the top of your :setting:`MIDDLEWARE` setting.
You can tell Django to stop reporting particular 404s by tweaking the
:setting:`IGNORABLE_404_URLS` setting. It should be a list of compiled
diff --git a/docs/ref/applications.txt b/docs/ref/applications.txt
index be761505fe..53d9bcd9b5 100644
--- a/docs/ref/applications.txt
+++ b/docs/ref/applications.txt
@@ -37,8 +37,8 @@ projects.
Applications include some combination of models, views, templates, template
tags, static files, URLs, middleware, etc. They're generally wired into
projects with the :setting:`INSTALLED_APPS` setting and optionally with other
-mechanisms such as URLconfs, the :setting:`MIDDLEWARE_CLASSES` setting, or
-template inheritance.
+mechanisms such as URLconfs, the :setting:`MIDDLEWARE` setting, or template
+inheritance.
It is important to understand that a Django application is just a set of code
that interacts with various parts of the framework. There's no such thing as
diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt
index e4af02c1a2..5057ef18b6 100644
--- a/docs/ref/checks.txt
+++ b/docs/ref/checks.txt
@@ -491,19 +491,19 @@ The following checks are run if you use the :option:`check --deploy` option:
* **security.W001**: You do not have
:class:`django.middleware.security.SecurityMiddleware` in your
- :setting:`MIDDLEWARE_CLASSES` so the :setting:`SECURE_HSTS_SECONDS`,
+ :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES` so the :setting:`SECURE_HSTS_SECONDS`,
:setting:`SECURE_CONTENT_TYPE_NOSNIFF`, :setting:`SECURE_BROWSER_XSS_FILTER`,
and :setting:`SECURE_SSL_REDIRECT` settings will have no effect.
* **security.W002**: You do not have
:class:`django.middleware.clickjacking.XFrameOptionsMiddleware` in your
- :setting:`MIDDLEWARE_CLASSES`, so your pages will not be served with an
+ :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES`, so your pages will not be served with an
``'x-frame-options'`` header. Unless there is a good reason for your
site to be served in a frame, you should consider enabling this
header to help prevent clickjacking attacks.
* **security.W003**: You don't appear to be using Django's built-in cross-site
request forgery protection via the middleware
(:class:`django.middleware.csrf.CsrfViewMiddleware` is not in your
- :setting:`MIDDLEWARE_CLASSES`). Enabling the middleware is the safest
+ :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES`). Enabling the middleware is the safest
approach to ensure you don't leave any holes.
* **security.W004**: You have not set a value for the
:setting:`SECURE_HSTS_SECONDS` setting. If your entire site is served only
@@ -540,7 +540,7 @@ The following checks are run if you use the :option:`check --deploy` option:
sessions.
* **security.W011**: You have
:class:`django.contrib.sessions.middleware.SessionMiddleware` in your
- :setting:`MIDDLEWARE_CLASSES`, but you have not set
+ :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES`, but you have not set
:setting:`SESSION_COOKIE_SECURE` to ``True``. Using a secure-only session
cookie makes it more difficult for network traffic sniffers to hijack user
sessions.
@@ -554,7 +554,7 @@ The following checks are run if you use the :option:`check --deploy` option:
sessions.
* **security.W014**: You have
:class:`django.contrib.sessions.middleware.SessionMiddleware` in your
- :setting:`MIDDLEWARE_CLASSES`, but you have not set
+ :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES`, but you have not set
:setting:`SESSION_COOKIE_HTTPONLY` to ``True``. Using an ``HttpOnly`` session
cookie makes it more difficult for cross-site scripting attacks to hijack user
sessions.
@@ -571,7 +571,7 @@ The following checks are run if you use the :option:`check --deploy` option:
deployment.
* **security.W019**: You have
:class:`django.middleware.clickjacking.XFrameOptionsMiddleware` in your
- :setting:`MIDDLEWARE_CLASSES`, but :setting:`X_FRAME_OPTIONS` is not set to
+ :setting:`MIDDLEWARE`/:setting:`MIDDLEWARE_CLASSES`, but :setting:`X_FRAME_OPTIONS` is not set to
``'DENY'``. The default is ``'SAMEORIGIN'``, but unless there is a good reason
for your site to serve other parts of itself in a frame, you should change
it to ``'DENY'``.
diff --git a/docs/ref/clickjacking.txt b/docs/ref/clickjacking.txt
index abac81dcd8..2f72e18d2f 100644
--- a/docs/ref/clickjacking.txt
+++ b/docs/ref/clickjacking.txt
@@ -56,9 +56,9 @@ Setting ``X-Frame-Options`` for all responses
To set the same ``X-Frame-Options`` value for all responses in your site, put
``'django.middleware.clickjacking.XFrameOptionsMiddleware'`` to
-:setting:`MIDDLEWARE_CLASSES`::
+:setting:`MIDDLEWARE`::
- MIDDLEWARE_CLASSES = [
+ MIDDLEWARE = [
...
'django.middleware.clickjacking.XFrameOptionsMiddleware',
...
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index eed7d4451c..66b116ad35 100644
--- a/docs/ref/contrib/admin/index.txt
+++ b/docs/ref/contrib/admin/index.txt
@@ -41,8 +41,8 @@ For reference, here are the requirements:
defined in your :setting:`TEMPLATES` as well as
:class:`django.contrib.auth.middleware.AuthenticationMiddleware` and
:class:`django.contrib.messages.middleware.MessageMiddleware` to
- :setting:`MIDDLEWARE_CLASSES`. (These are all active by default, so
- you only need to do this if you've manually tweaked the settings.)
+ :setting:`MIDDLEWARE`. These are all active by default, so you only need to
+ do this if you've manually tweaked the settings.
4. Determine which of your application's models should be editable in the
admin interface.
diff --git a/docs/ref/contrib/flatpages.txt b/docs/ref/contrib/flatpages.txt
index 3326a93ea8..580f864c34 100644
--- a/docs/ref/contrib/flatpages.txt
+++ b/docs/ref/contrib/flatpages.txt
@@ -53,7 +53,7 @@ Then either:
or:
3. Add ``'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'``
- to your :setting:`MIDDLEWARE_CLASSES` setting.
+ to your :setting:`MIDDLEWARE` setting.
4. Run the command :djadmin:`manage.py migrate <migrate>`.
@@ -144,8 +144,7 @@ can do all of the work.
methods. Only requests which are successfully routed to a view via
normal URL resolution apply view middleware.
-Note that the order of :setting:`MIDDLEWARE_CLASSES` matters. Generally, you
-can put
+Note that the order of :setting:`MIDDLEWARE` matters. Generally, you can put
:class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware` at the
end of the list. This means it will run first when processing the response, and
ensures that any other response-processing middlewares see the real flatpage
diff --git a/docs/ref/contrib/messages.txt b/docs/ref/contrib/messages.txt
index d425899cd9..414cf21116 100644
--- a/docs/ref/contrib/messages.txt
+++ b/docs/ref/contrib/messages.txt
@@ -27,14 +27,14 @@ already contains all the settings required to enable message functionality:
* ``'django.contrib.messages'`` is in :setting:`INSTALLED_APPS`.
-* :setting:`MIDDLEWARE_CLASSES` contains
+* :setting:`MIDDLEWARE` contains
``'django.contrib.sessions.middleware.SessionMiddleware'`` and
``'django.contrib.messages.middleware.MessageMiddleware'``.
The default :ref:`storage backend <message-storage-backends>` relies on
:doc:`sessions </topics/http/sessions>`. That's why ``SessionMiddleware``
must be enabled and appear before ``MessageMiddleware`` in
- :setting:`MIDDLEWARE_CLASSES`.
+ :setting:`MIDDLEWARE`.
* The ``'context_processors'`` option of the ``DjangoTemplates`` backend
defined in your :setting:`TEMPLATES` setting contains
@@ -42,8 +42,8 @@ already contains all the settings required to enable message functionality:
If you don't want to use messages, you can remove
``'django.contrib.messages'`` from your :setting:`INSTALLED_APPS`, the
-``MessageMiddleware`` line from :setting:`MIDDLEWARE_CLASSES`, and the
-``messages`` context processor from :setting:`TEMPLATES`.
+``MessageMiddleware`` line from :setting:`MIDDLEWARE`, and the ``messages``
+context processor from :setting:`TEMPLATES`.
Configuring the message engine
==============================
diff --git a/docs/ref/contrib/redirects.txt b/docs/ref/contrib/redirects.txt
index 2aadf8a45c..8af48ba8b2 100644
--- a/docs/ref/contrib/redirects.txt
+++ b/docs/ref/contrib/redirects.txt
@@ -18,7 +18,7 @@ To install the redirects app, follow these steps:
:ref:`is installed <enabling-the-sites-framework>`.
2. Add ``'django.contrib.redirects'`` to your :setting:`INSTALLED_APPS` setting.
3. Add ``'django.contrib.redirects.middleware.RedirectFallbackMiddleware'``
- to your :setting:`MIDDLEWARE_CLASSES` setting.
+ to your :setting:`MIDDLEWARE` setting.
4. Run the command :djadmin:`manage.py migrate <migrate>`.
How it works
@@ -49,9 +49,9 @@ given ``old_path`` with a site ID that corresponds to the
The middleware only gets activated for 404s -- not for 500s or responses of any
other status code.
-Note that the order of :setting:`MIDDLEWARE_CLASSES` matters. Generally, you
-can put :class:`~django.contrib.redirects.middleware.RedirectFallbackMiddleware`
-at the end of the list, because it's a last resort.
+Note that the order of :setting:`MIDDLEWARE` matters. Generally, you can put
+:class:`~django.contrib.redirects.middleware.RedirectFallbackMiddleware` at the
+end of the list, because it's a last resort.
For more on middleware, read the :doc:`middleware docs
</topics/http/middleware>`.
diff --git a/docs/ref/contrib/sites.txt b/docs/ref/contrib/sites.txt
index 2f312d04e0..ec2c1bf2b2 100644
--- a/docs/ref/contrib/sites.txt
+++ b/docs/ref/contrib/sites.txt
@@ -405,8 +405,8 @@ If you often use this pattern::
there is simple way to avoid repetitions. Add
:class:`django.contrib.sites.middleware.CurrentSiteMiddleware` to
-:setting:`MIDDLEWARE_CLASSES`. The middleware sets the ``site`` attribute on
-every request object, so you can use ``request.site`` to get the current site.
+:setting:`MIDDLEWARE`. The middleware sets the ``site`` attribute on every
+request object, so you can use ``request.site`` to get the current site.
How Django uses the sites framework
===================================
diff --git a/docs/ref/csrf.txt b/docs/ref/csrf.txt
index f59b45646d..277fd85720 100644
--- a/docs/ref/csrf.txt
+++ b/docs/ref/csrf.txt
@@ -27,10 +27,10 @@ How to use it
To take advantage of CSRF protection in your views, follow these steps:
-1. The CSRF middleware is activated by default in the
- :setting:`MIDDLEWARE_CLASSES` setting. If you override that setting, remember
- that ``'django.middleware.csrf.CsrfViewMiddleware'`` should come before any
- view middleware that assume that CSRF attacks have been dealt with.
+1. The CSRF middleware is activated by default in the :setting:`MIDDLEWARE`
+ setting. If you override that setting, remember that
+ ``'django.middleware.csrf.CsrfViewMiddleware'`` should come before any view
+ middleware that assume that CSRF attacks have been dealt with.
If you disabled it, which is not recommended, you can use
:func:`~django.views.decorators.csrf.csrf_protect` on particular views
diff --git a/docs/ref/middleware.txt b/docs/ref/middleware.txt
index 49062d3474..1e582d5724 100644
--- a/docs/ref/middleware.txt
+++ b/docs/ref/middleware.txt
@@ -77,6 +77,36 @@ issued by the middleware.
* Sends broken link notification emails to :setting:`MANAGERS` (see
:doc:`/howto/error-reporting`).
+Exception middleware
+--------------------
+
+.. module:: django.middleware.exception
+ :synopsis: Middleware to return responses for exceptions.
+
+.. class:: ExceptionMiddleware
+
+.. versionadded:: 1.10
+
+Catches exceptions raised during the request/response cycle and returns the
+appropriate response.
+
+* :class:`~django.http.Http404` is processed by
+ :data:`~django.conf.urls.handler404` (or a more friendly debug page if
+ :setting:`DEBUG=True <DEBUG>`).
+* :class:`~django.core.exceptions.PermissionDenied` is processed
+ by :data:`~django.conf.urls.handler403`.
+* ``MultiPartParserError`` is processed by :data:`~django.conf.urls.handler400`.
+* :class:`~django.core.exceptions.SuspiciousOperation` is processed by
+ :data:`~django.conf.urls.handler400` (or a more friendly debug page if
+ :setting:`DEBUG=True <DEBUG>`).
+* Any other exception is processed by :data:`~django.conf.urls.handler500`
+ (or a more friendly debug page if :setting:`DEBUG=True <DEBUG>`).
+
+Django uses this middleware regardless of whether or not you include it in
+:setting:`MIDDLEWARE`, however, you may want to subclass if your own middleware
+needs to transform any of these exceptions into the appropriate responses.
+:class:`~django.middleware.locale.LocaleMiddleware` does this, for example.
+
GZip middleware
---------------
diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt
index 64bd5960cd..96f5300f8b 100644
--- a/docs/ref/request-response.txt
+++ b/docs/ref/request-response.txt
@@ -176,9 +176,9 @@ All attributes should be considered read-only, unless stated otherwise.
An instance of :class:`~django.urls.ResolverMatch` representing the
resolved URL. This attribute is only set after URL resolving took place,
- which means it's available in all views but not in middleware methods
- which are executed before URL resolving takes place (like
- ``process_request()``, you can use ``process_view()`` instead).
+ which means it's available in all views but not in middleware which are
+ executed before URL resolving takes place (you can use it in
+ :meth:`process_view` though).
Attributes set by application code
----------------------------------
@@ -210,7 +210,7 @@ Attributes set by middleware
Some of the middleware included in Django's contrib apps set attributes on the
request. If you don't see the attribute on a request, be sure the appropriate
-middleware class is listed in :setting:`MIDDLEWARE_CLASSES`.
+middleware class is listed in :setting:`MIDDLEWARE`.
.. attribute:: HttpRequest.session
@@ -257,7 +257,9 @@ Methods
behind multiple proxies. One solution is to use middleware to rewrite
the proxy headers, as in the following example::
- class MultipleProxyMiddleware(object):
+ from django.django.utils.deprecation import MiddlewareMixin
+
+ class MultipleProxyMiddleware(MiddlewareMixin):
FORWARDED_FOR_FIELDS = [
'HTTP_X_FORWARDED_FOR',
'HTTP_X_FORWARDED_HOST',
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 838dde808a..a7801f715c 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -77,7 +77,7 @@ can be used as a subdomain wildcard: ``'.example.com'`` will match
``example.com``. A value of ``'*'`` will match anything; in this case you are
responsible to provide your own validation of the ``Host`` header (perhaps in a
middleware; if so this middleware must be listed first in
-:setting:`MIDDLEWARE_CLASSES`).
+:setting:`MIDDLEWARE`).
Django also allows the `fully qualified domain name (FQDN)`_ of any entries.
Some browsers include a trailing dot in the ``Host`` header which Django
@@ -1844,6 +1844,17 @@ Example: ``"http://media.example.com/"``
:setting:`MEDIA_URL` and :setting:`STATIC_URL` must have different
values. See :setting:`MEDIA_ROOT` for more details.
+.. setting:: MIDDLEWARE
+
+``MIDDLEWARE``
+--------------
+
+.. versionadded:: 1.10
+
+Default:: ``None``
+
+A list of middleware to use. See :doc:`/topics/http/middleware`.
+
.. setting:: MIDDLEWARE_CLASSES
``MIDDLEWARE_CLASSES``
@@ -1856,7 +1867,11 @@ Default::
'django.middleware.csrf.CsrfViewMiddleware',
]
-A list of middleware classes to use. See :doc:`/topics/http/middleware`.
+A list of middleware classes to use. This was the default setting used in
+Django 1.9 and earlier. Django 1.10 introduced a new style of middleware. If
+you have an older project using this setting you should :ref:`update any
+middleware you've written yourself <upgrading-middleware>` to the new style
+and then use the :setting:`MIDDLEWARE` setting.
.. setting:: MIGRATION_MODULES
@@ -3312,6 +3327,7 @@ HTTP
* :setting:`DISALLOWED_USER_AGENTS`
* :setting:`FORCE_SCRIPT_NAME`
* :setting:`INTERNAL_IPS`
+* :setting:`MIDDLEWARE`
* :setting:`MIDDLEWARE_CLASSES`
* Security
diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt
index f95ff1017f..1b527277af 100644
--- a/docs/ref/utils.txt
+++ b/docs/ref/utils.txt
@@ -173,6 +173,10 @@ The functions defined in this module share the following properties:
middleware functionality on a per-view basis. The middleware is created
with no params passed.
+ It assumes middleware that's compatible with the old style of Django 1.9
+ and earlier (having methods like ``process_request()``,
+ ``process_exception()``, and ``process_response()``).
+
.. function:: decorator_from_middleware_with_args(middleware_class)
Like ``decorator_from_middleware``, but returns a function
diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt
index b6ac9f5c89..13e5f44d5b 100644
--- a/docs/releases/1.10.txt
+++ b/docs/releases/1.10.txt
@@ -37,6 +37,17 @@ It also now includes trigram support, using the :lookup:`trigram_similar`
lookup, and the :class:`~django.contrib.postgres.search.TrigramSimilarity` and
:class:`~django.contrib.postgres.search.TrigramDistance` expressions.
+New-style middleware
+--------------------
+
+:doc:`A new style of middleware is introduced </topics/http/middleware>` to
+solve the lack of strict request/response layering of the old-style of
+middleware described in `DEP 0005
+<https://github.com/django/deps/blob/master/final/0005-improved-middleware.rst>`_.
+You'll need to :ref:`adapt old, custom middleware <upgrading-middleware>` and
+switch from the ``MIDDLEWARE_CLASSES`` setting to the new :setting:`MIDDLEWARE`
+setting to take advantage of the improvements.
+
Official support for Unicode usernames
--------------------------------------
diff --git a/docs/releases/1.5.txt b/docs/releases/1.5.txt
index 3ecdcca12e..21da0dca61 100644
--- a/docs/releases/1.5.txt
+++ b/docs/releases/1.5.txt
@@ -188,8 +188,7 @@ is an iterator.
Since :class:`~django.http.StreamingHttpResponse` does not have a ``content``
attribute, middleware that needs access to the response content must test for
-streaming responses and behave accordingly. See :ref:`response-middleware` for
-more information.
+streaming responses and behave accordingly.
``{% verbatim %}`` template tag
-------------------------------
diff --git a/docs/topics/auth/default.txt b/docs/topics/auth/default.txt
index 45526eb831..7e6794a97b 100644
--- a/docs/topics/auth/default.txt
+++ b/docs/topics/auth/default.txt
@@ -838,7 +838,7 @@ Session invalidation on password change
``SessionAuthenticationMiddleware`` is enabled. In older
versions, this protection only applies if
``django.contrib.auth.middleware.SessionAuthenticationMiddleware``
- is enabled in :setting:`MIDDLEWARE_CLASSES`.
+ is enabled in :setting:`MIDDLEWARE`.
If your :setting:`AUTH_USER_MODEL` inherits from
:class:`~django.contrib.auth.models.AbstractBaseUser` or implements its own
diff --git a/docs/topics/auth/index.txt b/docs/topics/auth/index.txt
index b57c2e7436..3224af74c7 100644
--- a/docs/topics/auth/index.txt
+++ b/docs/topics/auth/index.txt
@@ -60,7 +60,7 @@ startproject <startproject>`, these consist of two items listed in your
</ref/contrib/contenttypes>`, which allows permissions to be associated with
models you create.
-and these items in your :setting:`MIDDLEWARE_CLASSES` setting:
+and these items in your :setting:`MIDDLEWARE` setting:
1. :class:`~django.contrib.sessions.middleware.SessionMiddleware` manages
:doc:`sessions </topics/http/sessions>` across requests.
diff --git a/docs/topics/cache.txt b/docs/topics/cache.txt
index ad353e65e0..d955b853b4 100644
--- a/docs/topics/cache.txt
+++ b/docs/topics/cache.txt
@@ -447,9 +447,9 @@ Once the cache is set up, the simplest way to use caching is to cache your
entire site. You'll need to add
``'django.middleware.cache.UpdateCacheMiddleware'`` and
``'django.middleware.cache.FetchFromCacheMiddleware'`` to your
-:setting:`MIDDLEWARE_CLASSES` setting, as in this example::
+:setting:`MIDDLEWARE` setting, as in this example::
- MIDDLEWARE_CLASSES = [
+ MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
@@ -459,7 +459,7 @@ entire site. You'll need to add
No, that's not a typo: the "update" middleware must be first in the list,
and the "fetch" middleware must be last. The details are a bit obscure, but
- see `Order of MIDDLEWARE_CLASSES`_ below if you'd like the full story.
+ see `Order of MIDDLEWARE`_ below if you'd like the full story.
Then, add the following required settings to your Django settings file:
@@ -1217,11 +1217,11 @@ Example::
def myview(request):
...
-Order of ``MIDDLEWARE_CLASSES``
-===============================
+Order of ``MIDDLEWARE``
+=======================
If you use caching middleware, it's important to put each half in the right
-place within the :setting:`MIDDLEWARE_CLASSES` setting. That's because the cache
+place within the :setting:`MIDDLEWARE` setting. That's because the cache
middleware needs to know which headers by which to vary the cache storage.
Middleware always adds something to the ``Vary`` response header when it can.
diff --git a/docs/topics/http/_images/middleware.graffle b/docs/topics/http/_images/middleware.graffle
deleted file mode 100644
index cdefd4b810..0000000000
--- a/docs/topics/http/_images/middleware.graffle
+++ /dev/null
@@ -1,957 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>ActiveLayerIndex</key>
- <integer>0</integer>
- <key>ApplicationVersion</key>
- <array>
- <string>com.omnigroup.OmniGrafflePro</string>
- <string>139.16.0.171715</string>
- </array>
- <key>AutoAdjust</key>
- <true/>
- <key>BackgroundGraphic</key>
- <dict>
- <key>Bounds</key>
- <string>{{0, 0}, {559.28997802734375, 782.8900146484375}}</string>
- <key>Class</key>
- <string>SolidGraphic</string>
- <key>ID</key>
- <integer>2</integer>
- <key>Style</key>
- <dict>
- <key>shadow</key>
- <dict>
- <key>Draws</key>
- <string>NO</string>
- </dict>
- <key>stroke</key>
- <dict>
- <key>Draws</key>
- <string>NO</string>
- </dict>
- </dict>
- </dict>
- <key>BaseZoom</key>
- <integer>0</integer>
- <key>CanvasOrigin</key>
- <string>{0, 0}</string>
- <key>ColumnAlign</key>
- <integer>1</integer>
- <key>ColumnSpacing</key>
- <real>36</real>
- <key>CreationDate</key>
- <string>2012-12-09 18:55:12 +0000</string>
- <key>Creator</key>
- <string>Aymeric Augustin</string>
- <key>DisplayScale</key>
- <string>1.000 cm = 1.000 cm</string>
- <key>GraphDocumentVersion</key>
- <integer>8</integer>
- <key>GraphicsList</key>
- <array>
- <dict>
- <key>Bounds</key>
- <string>{{144, 405}, {369, 27}}</string>
- <key>Class</key>
- <string>ShapedGraphic</string>
- <key>ID</key>
- <integer>33</integer>
- <key>Shape</key>
- <string>Bezier</string>
- <key>ShapeData</key>
- <dict>
- <key>UnitPoints</key>
- <array>
- <string>{-0.5, -0.5}</string>
- <string>{-0.5, -0.5}</string>
- <string>{0.47959183673469341, -0.5}</string>
- <string>{0.47959183673469408, -0.5}</string>
- <string>{0.47959183673469341, -0.5}</string>
- <string>{0.5, 0}</string>
- <string>{0.5, 0}</string>
- <string>{0.5, 0}</string>
- <string>{0.47959183673469408, 0.5}</string>
- <string>{0.47959183673469408, 0.5}</string>
- <string>{0.47959183673469408, 0.5}</string>
- <string>{-0.5, 0.5}</string>
- <string>{-0.5, 0.5}</string>
- <string>{-0.5, 0.5}</string>
- <string>{-0.47560975609756084, 0}</string>
- <string>{-0.47560975609756084, 0}</string>
- <string>{-0.47560975609756084, 0}</string>
- <string>{-0.5, -0.5}</string>
- </array>
- </dict>
- <key>Text</key>
- <dict>
- <key>Text</key>
- <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
-\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 view function}</string>
- </dict>
- </dict>
- <dict>
- <key>Bounds</key>
- <string>{{229.5, 238.5}, {297, 36}}</string>
- <key>Class</key>
- <string>ShapedGraphic</string>
- <key>ID</key>
- <integer>31</integer>
- <key>Rotation</key>
- <real>270</real>
- <key>Shape</key>
- <string>AdjustableArrow</string>
- <key>ShapeData</key>
- <dict>
- <key>width</key>
- <real>27</real>
- </dict>
- <key>Style</key>
- <dict>
- <key>fill</key>
- <dict>
- <key>Color</key>
- <dict>
- <key>a</key>
- <string>0.8</string>
- <key>b</key>
- <string>1</string>
- <key>g</key>
- <string>1</string>
- <key>r</key>
- <string>1</string>
- </dict>
- <key>MiddleFraction</key>
- <real>0.70634919404983521</real>
- </dict>
- <key>shadow</key>
- <dict>
- <key>Color</key>
- <dict>
- <key>a</key>
- <string>0.4</string>
- <key>b</key>
- <string>0</string>
- <key>g</key>
- <string>0</string>
- <key>r</key>
- <string>0</string>
- </dict>
- <key>Draws</key>
- <string>NO</string>
- <key>Fuzziness</key>
- <real>0.0</real>
- <key>ShadowVector</key>
- <string>{0, 2}</string>
- </dict>
- <key>stroke</key>
- <dict>
- <key>Color</key>
- <dict>
- <key>b</key>
- <string>0</string>
- <key>g</key>
- <string>0</string>
- <key>r</key>
- <string>1</string>
- </dict>
- <key>Pattern</key>
- <integer>1</integer>
- </dict>
- </dict>
- <key>Text</key>
- <dict>
- <key>Text</key>
- <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
-\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
-{\colortbl;\red255\green255\blue255;\red255\green0\blue0;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf2 process_exception}</string>
- </dict>
- <key>TextRelativeArea</key>
- <string>{{0.125, 0.25}, {0.75, 0.5}}</string>
- <key>isConnectedShape</key>
- <true/>
- </dict>
- <dict>
- <key>Bounds</key>
- <string>{{328.5, 229.5}, {315, 36}}</string>
- <key>Class</key>
- <string>ShapedGraphic</string>
- <key>ID</key>
- <integer>30</integer>
- <key>Rotation</key>
- <real>270</real>
- <key>Shape</key>
- <string>AdjustableArrow</string>
- <key>ShapeData</key>
- <dict>
- <key>width</key>
- <real>27</real>
- </dict>
- <key>Style</key>
- <dict>
- <key>fill</key>
- <dict>
- <key>Color</key>
- <dict>
- <key>a</key>
- <string>0.8</string>
- <key>b</key>
- <string>1</string>
- <key>g</key>
- <string>1</string>
- <key>r</key>
- <string>1</string>
- </dict>
- <key>MiddleFraction</key>
- <real>0.70634919404983521</real>
- </dict>
- <key>shadow</key>
- <dict>
- <key>Color</key>
- <dict>
- <key>a</key>
- <string>0.4</string>
- <key>b</key>
- <string>0</string>
- <key>g</key>
- <string>0</string>
- <key>r</key>
- <string>0</string>
- </dict>
- <key>Draws</key>
- <string>NO</string>
- <key>Fuzziness</key>
- <real>0.0</real>
- <key>ShadowVector</key>
- <string>{0, 2}</string>
- </dict>
- <key>stroke</key>
- <dict>
- <key>Color</key>
- <dict>
- <key>b</key>
- <string>0</string>
- <key>g</key>
- <string>0.501961</string>
- <key>r</key>
- <string>0</string>
- </dict>
- </dict>
- </dict>
- <key>Text</key>
- <dict>
- <key>Text</key>
- <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
-\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
-{\colortbl;\red255\green255\blue255;\red0\green128\blue0;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf2 process_response}</string>
- </dict>
- <key>TextRelativeArea</key>
- <string>{{0.125, 0.25}, {0.75, 0.5}}</string>
- <key>isConnectedShape</key>
- <true/>
- </dict>
- <dict>
- <key>Bounds</key>
- <string>{{283.5, 238.5}, {297, 36}}</string>
- <key>Class</key>
- <string>ShapedGraphic</string>
- <key>ID</key>
- <integer>29</integer>
- <key>Rotation</key>
- <real>270</real>
- <key>Shape</key>
- <string>AdjustableArrow</string>
- <key>ShapeData</key>
- <dict>
- <key>width</key>
- <real>27</real>
- </dict>
- <key>Style</key>
- <dict>
- <key>fill</key>
- <dict>
- <key>Color</key>
- <dict>
- <key>a</key>
- <string>0.8</string>
- <key>b</key>
- <string>1</string>
- <key>g</key>
- <string>1</string>
- <key>r</key>
- <string>1</string>
- </dict>
- <key>MiddleFraction</key>
- <real>0.70634919404983521</real>
- </dict>
- <key>shadow</key>
- <dict>
- <key>Color</key>
- <dict>
- <key>a</key>
- <string>0.4</string>
- <key>b</key>
- <string>0</string>
- <key>g</key>
- <string>0</string>
- <key>r</key>
- <string>0</string>
- </dict>
- <key>Draws</key>
- <string>NO</string>
- <key>Fuzziness</key>
- <real>0.0</real>
- <key>ShadowVector</key>
- <string>{0, 2}</string>
- </dict>
- <key>stroke</key>
- <dict>
- <key>Color</key>
- <dict>
- <key>b</key>
- <string>0</string>
- <key>g</key>
- <string>0.501961</string>
- <key>r</key>
- <string>0</string>
- </dict>
- <key>Pattern</key>
- <integer>1</integer>
- </dict>
- </dict>
- <key>Text</key>
- <dict>
- <key>Text</key>
- <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
-\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
-{\colortbl;\red255\green255\blue255;\red0\green128\blue0;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf2 process_template_response}</string>
- </dict>
- <key>TextRelativeArea</key>
- <string>{{0.125, 0.25}, {0.75, 0.5}}</string>
- <key>isConnectedShape</key>
- <true/>
- </dict>
- <dict>
- <key>Bounds</key>
- <string>{{27, 243}, {288, 36}}</string>
- <key>Class</key>
- <string>ShapedGraphic</string>
- <key>ID</key>
- <integer>28</integer>
- <key>Rotation</key>
- <real>90</real>
- <key>Shape</key>
- <string>AdjustableArrow</string>
- <key>ShapeData</key>
- <dict>
- <key>width</key>
- <real>27</real>
- </dict>
- <key>Style</key>
- <dict>
- <key>fill</key>
- <dict>
- <key>Color</key>
- <dict>
- <key>a</key>
- <string>0.8</string>
- <key>b</key>
- <string>1</string>
- <key>g</key>
- <string>1</string>
- <key>r</key>
- <string>1</string>
- </dict>
- <key>MiddleFraction</key>
- <real>0.70634919404983521</real>
- </dict>
- <key>shadow</key>
- <dict>
- <key>Color</key>
- <dict>
- <key>a</key>
- <string>0.4</string>
- <key>b</key>
- <string>0</string>
- <key>g</key>
- <string>0</string>
- <key>r</key>
- <string>0</string>
- </dict>
- <key>Draws</key>
- <string>NO</string>
- <key>Fuzziness</key>
- <real>0.0</real>
- <key>ShadowVector</key>
- <string>{0, 2}</string>
- </dict>
- <key>stroke</key>
- <dict>
- <key>Color</key>
- <dict>
- <key>b</key>
- <string>0</string>
- <key>g</key>
- <string>0.501961</string>
- <key>r</key>
- <string>0</string>
- </dict>
- </dict>
- </dict>
- <key>Text</key>
- <dict>
- <key>Text</key>
- <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
-\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
-{\colortbl;\red255\green255\blue255;\red0\green128\blue0;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf2 process_view}</string>
- </dict>
- <key>TextRelativeArea</key>
- <string>{{0.125, 0.25}, {0.75, 0.5}}</string>
- <key>isConnectedShape</key>
- <true/>
- </dict>
- <dict>
- <key>Bounds</key>
- <string>{{-40.500000000767386, 220.49999999804004}, {297, 36}}</string>
- <key>Class</key>
- <string>ShapedGraphic</string>
- <key>ID</key>
- <integer>27</integer>
- <key>Rotation</key>
- <real>90</real>
- <key>Shape</key>
- <string>AdjustableArrow</string>
- <key>ShapeData</key>
- <dict>
- <key>width</key>
- <real>27</real>
- </dict>
- <key>Style</key>
- <dict>
- <key>fill</key>
- <dict>
- <key>Color</key>
- <dict>
- <key>a</key>
- <string>0.8</string>
- <key>b</key>
- <string>1</string>
- <key>g</key>
- <string>1</string>
- <key>r</key>
- <string>1</string>
- </dict>
- <key>MiddleFraction</key>
- <real>0.70634919404983521</real>
- </dict>
- <key>shadow</key>
- <dict>
- <key>Color</key>
- <dict>
- <key>a</key>
- <string>0.4</string>
- <key>b</key>
- <string>0</string>
- <key>g</key>
- <string>0</string>
- <key>r</key>
- <string>0</string>
- </dict>
- <key>Draws</key>
- <string>NO</string>
- <key>Fuzziness</key>
- <real>0.0</real>
- <key>ShadowVector</key>
- <string>{0, 2}</string>
- </dict>
- <key>stroke</key>
- <dict>
- <key>Color</key>
- <dict>
- <key>b</key>
- <string>0</string>
- <key>g</key>
- <string>0.501961</string>
- <key>r</key>
- <string>0</string>
- </dict>
- </dict>
- </dict>
- <key>Text</key>
- <dict>
- <key>Text</key>
- <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
-\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
-{\colortbl;\red255\green255\blue255;\red0\green128\blue0;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf2 process_request}</string>
- </dict>
- <key>TextRelativeArea</key>
- <string>{{0.125, 0.25}, {0.75, 0.5}}</string>
- <key>isConnectedShape</key>
- <true/>
- </dict>
- <dict>
- <key>Bounds</key>
- <string>{{360, 63}, {144, 27}}</string>
- <key>Class</key>
- <string>ShapedGraphic</string>
- <key>ID</key>
- <integer>12</integer>
- <key>Magnets</key>
- <array>
- <string>{0, 1}</string>
- <string>{0, -1}</string>
- <string>{1, 0}</string>
- <string>{-1, 0}</string>
- </array>
- <key>Shape</key>
- <string>Rectangle</string>
- <key>Text</key>
- <dict>
- <key>Text</key>
- <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
-\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 HttpResponse}</string>
- </dict>
- </dict>
- <dict>
- <key>Bounds</key>
- <string>{{72, 63}, {144, 27}}</string>
- <key>Class</key>
- <string>ShapedGraphic</string>
- <key>ID</key>
- <integer>11</integer>
- <key>Magnets</key>
- <array>
- <string>{0, 1}</string>
- <string>{0, -1}</string>
- <string>{1, 0}</string>
- <string>{-1, 0}</string>
- </array>
- <key>Shape</key>
- <string>Rectangle</string>
- <key>Text</key>
- <dict>
- <key>Text</key>
- <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
-\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 HttpRequest}</string>
- </dict>
- </dict>
- <dict>
- <key>Bounds</key>
- <string>{{72, 324}, {432, 27}}</string>
- <key>Class</key>
- <string>ShapedGraphic</string>
- <key>ID</key>
- <integer>10</integer>
- <key>Magnets</key>
- <array>
- <string>{0, 1}</string>
- <string>{0, -1}</string>
- <string>{1, 0}</string>
- <string>{-1, 0}</string>
- </array>
- <key>Shape</key>
- <string>Rectangle</string>
- <key>Style</key>
- <dict>
- <key>fill</key>
- <dict>
- <key>FillType</key>
- <integer>2</integer>
- <key>GradientAngle</key>
- <real>90</real>
- <key>GradientColor</key>
- <dict>
- <key>w</key>
- <string>0.666667</string>
- </dict>
- </dict>
- <key>stroke</key>
- <dict>
- <key>CornerRadius</key>
- <real>5</real>
- </dict>
- </dict>
- <key>Text</key>
- <dict>
- <key>Text</key>
- <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
-\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 MessageMiddleware}</string>
- </dict>
- </dict>
- <dict>
- <key>Bounds</key>
- <string>{{72, 279}, {432, 27}}</string>
- <key>Class</key>
- <string>ShapedGraphic</string>
- <key>ID</key>
- <integer>9</integer>
- <key>Magnets</key>
- <array>
- <string>{0, 1}</string>
- <string>{0, -1}</string>
- <string>{1, 0}</string>
- <string>{-1, 0}</string>
- </array>
- <key>Shape</key>
- <string>Rectangle</string>
- <key>Style</key>
- <dict>
- <key>fill</key>
- <dict>
- <key>FillType</key>
- <integer>2</integer>
- <key>GradientAngle</key>
- <real>90</real>
- <key>GradientColor</key>
- <dict>
- <key>w</key>
- <string>0.666667</string>
- </dict>
- </dict>
- <key>stroke</key>
- <dict>
- <key>CornerRadius</key>
- <real>5</real>
- </dict>
- </dict>
- <key>Text</key>
- <dict>
- <key>Text</key>
- <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
-\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 AuthenticationMiddleware}</string>
- </dict>
- </dict>
- <dict>
- <key>Bounds</key>
- <string>{{72, 234}, {432, 27}}</string>
- <key>Class</key>
- <string>ShapedGraphic</string>
- <key>ID</key>
- <integer>8</integer>
- <key>Magnets</key>
- <array>
- <string>{0, 1}</string>
- <string>{0, -1}</string>
- <string>{1, 0}</string>
- <string>{-1, 0}</string>
- </array>
- <key>Shape</key>
- <string>Rectangle</string>
- <key>Style</key>
- <dict>
- <key>fill</key>
- <dict>
- <key>FillType</key>
- <integer>2</integer>
- <key>GradientAngle</key>
- <real>90</real>
- <key>GradientColor</key>
- <dict>
- <key>w</key>
- <string>0.666667</string>
- </dict>
- </dict>
- <key>stroke</key>
- <dict>
- <key>CornerRadius</key>
- <real>5</real>
- </dict>
- </dict>
- <key>Text</key>
- <dict>
- <key>Text</key>
- <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
-\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 CsrfViewMiddleware}</string>
- </dict>
- </dict>
- <dict>
- <key>Bounds</key>
- <string>{{72, 189}, {432, 27}}</string>
- <key>Class</key>
- <string>ShapedGraphic</string>
- <key>ID</key>
- <integer>7</integer>
- <key>Magnets</key>
- <array>
- <string>{0, 1}</string>
- <string>{0, -1}</string>
- <string>{1, 0}</string>
- <string>{-1, 0}</string>
- </array>
- <key>Shape</key>
- <string>Rectangle</string>
- <key>Style</key>
- <dict>
- <key>fill</key>
- <dict>
- <key>FillType</key>
- <integer>2</integer>
- <key>GradientAngle</key>
- <real>90</real>
- <key>GradientColor</key>
- <dict>
- <key>w</key>
- <string>0.666667</string>
- </dict>
- </dict>
- <key>stroke</key>
- <dict>
- <key>CornerRadius</key>
- <real>5</real>
- </dict>
- </dict>
- <key>Text</key>
- <dict>
- <key>Text</key>
- <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
-\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 SessionMiddleware}</string>
- </dict>
- </dict>
- <dict>
- <key>Bounds</key>
- <string>{{72, 144}, {432, 27}}</string>
- <key>Class</key>
- <string>ShapedGraphic</string>
- <key>ID</key>
- <integer>6</integer>
- <key>Magnets</key>
- <array>
- <string>{0, 1}</string>
- <string>{0, -1}</string>
- <string>{1, 0}</string>
- <string>{-1, 0}</string>
- </array>
- <key>Shape</key>
- <string>Rectangle</string>
- <key>Style</key>
- <dict>
- <key>fill</key>
- <dict>
- <key>FillType</key>
- <integer>2</integer>
- <key>GradientAngle</key>
- <real>90</real>
- <key>GradientColor</key>
- <dict>
- <key>w</key>
- <string>0.666667</string>
- </dict>
- </dict>
- <key>stroke</key>
- <dict>
- <key>CornerRadius</key>
- <real>5</real>
- </dict>
- </dict>
- <key>Text</key>
- <dict>
- <key>Text</key>
- <string>{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340
-\cocoascreenfonts1{\fonttbl\f0\fmodern\fcharset0 Courier;}
-{\colortbl;\red255\green255\blue255;}
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
-
-\f0\fs24 \cf0 CommonMiddleware}</string>
- </dict>
- </dict>
- </array>
- <key>GridInfo</key>
- <dict>
- <key>ShowsGrid</key>
- <string>YES</string>
- <key>SnapsToGrid</key>
- <string>YES</string>
- </dict>
- <key>GuidesLocked</key>
- <string>NO</string>
- <key>GuidesVisible</key>
- <string>YES</string>
- <key>HPages</key>
- <integer>1</integer>
- <key>ImageCounter</key>
- <integer>1</integer>
- <key>KeepToScale</key>
- <false/>
- <key>Layers</key>
- <array>
- <dict>
- <key>Lock</key>
- <string>NO</string>
- <key>Name</key>
- <string>Calque 1</string>
- <key>Print</key>
- <string>YES</string>
- <key>View</key>
- <string>YES</string>
- </dict>
- </array>
- <key>LayoutInfo</key>
- <dict>
- <key>Animate</key>
- <string>NO</string>
- <key>circoMinDist</key>
- <real>18</real>
- <key>circoSeparation</key>
- <real>0.0</real>
- <key>layoutEngine</key>
- <string>dot</string>
- <key>neatoSeparation</key>
- <real>0.0</real>
- <key>twopiSeparation</key>
- <real>0.0</real>
- </dict>
- <key>LinksVisible</key>
- <string>NO</string>
- <key>MagnetsVisible</key>
- <string>NO</string>
- <key>MasterSheets</key>
- <array/>
- <key>ModificationDate</key>
- <string>2012-12-09 19:48:54 +0000</string>
- <key>Modifier</key>
- <string>Aymeric Augustin</string>
- <key>NotesVisible</key>
- <string>NO</string>
- <key>Orientation</key>
- <integer>2</integer>
- <key>OriginVisible</key>
- <string>NO</string>
- <key>PageBreaks</key>
- <string>YES</string>
- <key>PrintInfo</key>
- <dict>
- <key>NSBottomMargin</key>
- <array>
- <string>float</string>
- <string>41</string>
- </array>
- <key>NSHorizonalPagination</key>
- <array>
- <string>coded</string>
- <string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG</string>
- </array>
- <key>NSLeftMargin</key>
- <array>
- <string>float</string>
- <string>18</string>
- </array>
- <key>NSPaperSize</key>
- <array>
- <string>size</string>
- <string>{595.28997802734375, 841.8900146484375}</string>
- </array>
- <key>NSPrintReverseOrientation</key>
- <array>
- <string>int</string>
- <string>0</string>
- </array>
- <key>NSRightMargin</key>
- <array>
- <string>float</string>
- <string>18</string>
- </array>
- <key>NSTopMargin</key>
- <array>
- <string>float</string>
- <string>18</string>
- </array>
- </dict>
- <key>PrintOnePage</key>
- <false/>
- <key>ReadOnly</key>
- <string>NO</string>
- <key>RowAlign</key>
- <integer>1</integer>
- <key>RowSpacing</key>
- <real>36</real>
- <key>SheetTitle</key>
- <string>Canevas 1</string>
- <key>SmartAlignmentGuidesActive</key>
- <string>YES</string>
- <key>SmartDistanceGuidesActive</key>
- <string>YES</string>
- <key>UniqueID</key>
- <integer>1</integer>
- <key>UseEntirePage</key>
- <false/>
- <key>VPages</key>
- <integer>1</integer>
- <key>WindowInfo</key>
- <dict>
- <key>CurrentSheet</key>
- <integer>0</integer>
- <key>ExpandedCanvases</key>
- <array/>
- <key>Frame</key>
- <string>{{248, 4}, {694, 874}}</string>
- <key>ListView</key>
- <true/>
- <key>OutlineWidth</key>
- <integer>142</integer>
- <key>RightSidebar</key>
- <false/>
- <key>ShowRuler</key>
- <true/>
- <key>Sidebar</key>
- <true/>
- <key>SidebarWidth</key>
- <integer>120</integer>
- <key>VisibleRegion</key>
- <string>{{0, 0}, {559, 735}}</string>
- <key>Zoom</key>
- <real>1</real>
- <key>ZoomValues</key>
- <array>
- <array>
- <string>Canevas 1</string>
- <real>1</real>
- <real>1</real>
- </array>
- </array>
- </dict>
-</dict>
-</plist>
diff --git a/docs/topics/http/_images/middleware.svg b/docs/topics/http/_images/middleware.svg
deleted file mode 100644
index 4da8d22da8..0000000000
--- a/docs/topics/http/_images/middleware.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="52 47 481 409" width="481pt" height="409pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2012-12-09 19:48Z</dc:date><!-- Produced by OmniGraffle Professional 5.4.2 --></metadata><defs><filter id="Shadow" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" result="blur" stdDeviation="3.488"/><feOffset in="blur" result="offset" dx="0" dy="4"/><feFlood flood-color="black" flood-opacity=".75" result="flood"/><feComposite in="flood" in2="offset" operator="in"/></filter><linearGradient x1="0" x2="1" id="Gradient" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="white"/><stop offset="1" stop-color="#aaa"/></linearGradient><linearGradient id="Obj_Gradient" xl:href="#Gradient" gradientTransform="translate(288 144) rotate(90) scale(27)"/><font-face font-family="Courier" font-size="12" units-per-em="1000" underline-position="-178.22266" underline-thickness="57.617188" slope="0" x-height="462.40234" cap-height="594.72656" ascent="753.90625" descent="-246.09375" font-weight="500"><font-face-src><font-face-name name="Courier"/></font-face-src></font-face><linearGradient id="Obj_Gradient_2" xl:href="#Gradient" gradientTransform="translate(288 189) rotate(90) scale(27)"/><linearGradient id="Obj_Gradient_3" xl:href="#Gradient" gradientTransform="translate(288 234) rotate(90) scale(27)"/><linearGradient id="Obj_Gradient_4" xl:href="#Gradient" gradientTransform="translate(288 279) rotate(90) scale(27)"/><linearGradient id="Obj_Gradient_5" xl:href="#Gradient" gradientTransform="translate(288 324) rotate(90) scale(27)"/><font-face font-family="Helvetica" font-size="12" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="522.94922" cap-height="717.28516" ascent="770.01953" descent="-229.98047" font-weight="500"><font-face-src><font-face-name name="Helvetica"/></font-face-src></font-face></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canevas 1</title><rect fill="white" width="559.28998" height="782.89"/><g><title>Calque 1</title><g><use xl:href="#id6_Graphic" filter="url(#Shadow)"/><use xl:href="#id7_Graphic" filter="url(#Shadow)"/><use xl:href="#id8_Graphic" filter="url(#Shadow)"/><use xl:href="#id9_Graphic" filter="url(#Shadow)"/><use xl:href="#id10_Graphic" filter="url(#Shadow)"/><use xl:href="#id11_Graphic" filter="url(#Shadow)"/><use xl:href="#id12_Graphic" filter="url(#Shadow)"/><use xl:href="#id33_Graphic" filter="url(#Shadow)"/></g><g id="id6_Graphic"><path d="M 77 144 L 499 144 C 501.76142 144 504 146.23858 504 149 L 504 166 C 504 168.76142 501.76142 171 499 171 L 77 171 C 74.238576 171 72 168.76142 72 166 C 72 166 72 166 72 166 L 72 149 C 72 146.23858 74.238576 144 77 144 C 77 144 77 144 77 144 Z" fill="url(#Obj_Gradient)"/><path d="M 77 144 L 499 144 C 501.76142 144 504 146.23858 504 149 L 504 166 C 504 168.76142 501.76142 171 499 171 L 77 171 C 74.238576 171 72 168.76142 72 166 C 72 166 72 166 72 166 L 72 149 C 72 146.23858 74.238576 144 77 144 C 77 144 77 144 77 144 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 150.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" fill="black" x="153.390625" y="11" textLength="115.21875">CommonMiddleware</tspan></text></g><g id="id7_Graphic"><path d="M 77 189 L 499 189 C 501.76142 189 504 191.23858 504 194 L 504 211 C 504 213.76142 501.76142 216 499 216 L 77 216 C 74.238576 216 72 213.76142 72 211 C 72 211 72 211 72 211 L 72 194 C 72 191.23858 74.238576 189 77 189 C 77 189 77 189 77 189 Z" fill="url(#Obj_Gradient_2)"/><path d="M 77 189 L 499 189 C 501.76142 189 504 191.23858 504 194 L 504 211 C 504 213.76142 501.76142 216 499 216 L 77 216 C 74.238576 216 72 213.76142 72 211 C 72 211 72 211 72 211 L 72 194 C 72 191.23858 74.238576 189 77 189 C 77 189 77 189 77 189 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 195.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="149.79004" y="11" textLength="122.41992">SessionMiddleware</tspan></text></g><g id="id8_Graphic"><path d="M 77 234 L 499 234 C 501.76142 234 504 236.23858 504 239 L 504 256 C 504 258.76142 501.76142 261 499 261 L 77 261 C 74.238576 261 72 258.76142 72 256 C 72 256 72 256 72 256 L 72 239 C 72 236.23858 74.238576 234 77 234 C 77 234 77 234 77 234 Z" fill="url(#Obj_Gradient_3)"/><path d="M 77 234 L 499 234 C 501.76142 234 504 236.23858 504 239 L 504 256 C 504 258.76142 501.76142 261 499 261 L 77 261 C 74.238576 261 72 258.76142 72 256 C 72 256 72 256 72 256 L 72 239 C 72 236.23858 74.238576 234 77 234 C 77 234 77 234 77 234 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 240.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="146.18945" y="11" textLength="129.62109">CsrfViewMiddleware</tspan></text></g><g id="id9_Graphic"><path d="M 77 279 L 499 279 C 501.76142 279 504 281.23858 504 284 L 504 301 C 504 303.76142 501.76142 306 499 306 L 77 306 C 74.238576 306 72 303.76142 72 301 C 72 301 72 301 72 301 L 72 284 C 72 281.23858 74.238576 279 77 279 C 77 279 77 279 77 279 Z" fill="url(#Obj_Gradient_4)"/><path d="M 77 279 L 499 279 C 501.76142 279 504 281.23858 504 284 L 504 301 C 504 303.76142 501.76142 306 499 306 L 77 306 C 74.238576 306 72 303.76142 72 301 C 72 301 72 301 72 301 L 72 284 C 72 281.23858 74.238576 279 77 279 C 77 279 77 279 77 279 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 285.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="124.58594" y="11" textLength="172.82812">AuthenticationMiddleware</tspan></text></g><g id="id10_Graphic"><path d="M 77 324 L 499 324 C 501.76142 324 504 326.23858 504 329 L 504 346 C 504 348.76142 501.76142 351 499 351 L 77 351 C 74.238576 351 72 348.76142 72 346 C 72 346 72 346 72 346 L 72 329 C 72 326.23858 74.238576 324 77 324 C 77 324 77 324 77 324 Z" fill="url(#Obj_Gradient_5)"/><path d="M 77 324 L 499 324 C 501.76142 324 504 326.23858 504 329 L 504 346 C 504 348.76142 501.76142 351 499 351 L 77 351 C 74.238576 351 72 348.76142 72 346 C 72 346 72 346 72 346 L 72 329 C 72 326.23858 74.238576 324 77 324 C 77 324 77 324 77 324 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 330.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="149.79004" y="11" textLength="122.41992">MessageMiddleware</tspan></text></g><g id="id11_Graphic"><rect x="72" y="63" width="144" height="27" fill="white"/><rect x="72" y="63" width="144" height="27" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(77 69.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="27.393555" y="11" textLength="79.21289">HttpRequest</tspan></text></g><g id="id12_Graphic"><rect x="360" y="63" width="144" height="27" fill="white"/><rect x="360" y="63" width="144" height="27" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(365 69.5)" fill="black"><tspan font-family="Courier" font-size="12" font-weight="500" x="23.792969" y="11" textLength="86.41406">HttpResponse</tspan></text></g><path d="M 99 90 L 117 90 L 117 360 L 126 360 L 108 387 L 90 360 L 99 360 Z" fill="white" fill-opacity=".8"/><path d="M 99 90 L 117 90 L 117 360 L 126 360 L 108 387 L 90 360 L 99 360 Z" stroke="green" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(115 132.125) rotate(90)" fill="green"><tspan font-family="Courier" font-size="12" font-weight="500" fill="green" x="52.36621" y="11" textLength="108.01758">process_request</tspan></text><path d="M 162 117 L 180 117 L 180 378 L 189 378 L 171 405 L 153 378 L 162 378 Z" fill="white" fill-opacity=".8"/><path d="M 162 117 L 180 117 L 180 378 L 189 378 L 171 405 L 153 378 L 162 378 Z" stroke="green" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(178 158) rotate(90)" fill="green"><tspan font-family="Courier" font-size="12" font-weight="500" fill="green" x="59.79297" y="11" textLength="86.41406">process_view</tspan></text><path d="M 441 405 L 423 405 L 423 135 L 414 135 L 432 108 L 450 135 L 441 135 Z" fill="white" fill-opacity=".8"/><path d="M 441 405 L 423 405 L 423 135 L 414 135 L 432 108 L 450 135 L 441 135 Z" stroke="green" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="4,4"/><text transform="translate(425 362.875) rotate(-90)" fill="green"><tspan font-family="Courier" font-size="12" font-weight="500" fill="green" x="16.360352" y="11" textLength="180.0293">process_template_response</tspan></text><path d="M 495 405 L 477 405 L 477 117 L 468 117 L 486 90 L 504 117 L 495 117 Z" fill="white" fill-opacity=".8"/><path d="M 495 405 L 477 405 L 477 117 L 468 117 L 486 90 L 504 117 L 495 117 Z" stroke="green" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(479 360.625) rotate(-90)" fill="green"><tspan font-family="Courier" font-size="12" font-weight="500" fill="green" x="55.515625" y="11" textLength="115.21875">process_response</tspan></text><path d="M 387 405 L 369 405 L 369 135 L 360 135 L 378 108 L 396 135 L 387 135 Z" fill="white" fill-opacity=".8"/><path d="M 387 405 L 369 405 L 369 135 L 360 135 L 378 108 L 396 135 L 387 135 Z" stroke="red" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" stroke-dasharray="4,4"/><text transform="translate(371 362.875) rotate(-90)" fill="red"><tspan font-family="Courier" font-size="12" font-weight="500" fill="red" x="45.16504" y="11" textLength="122.41992">process_exception</tspan></text><g id="id33_Graphic"><path d="M 144 405 L 505.4694 405 L 513 418.5 L 505.4694 432 L 144 432 L 153 418.5 Z" fill="white"/><path d="M 144 405 L 505.4694 405 L 513 418.5 L 505.4694 432 L 144 432 L 153 418.5 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(149 411.5)" fill="black"><tspan font-family="Helvetica" font-size="12" font-weight="500" fill="black" x="144.81543" y="11" textLength="69.36914">view function</tspan></text></g></g></g></svg>
diff --git a/docs/topics/http/middleware.txt b/docs/topics/http/middleware.txt
index 16fdace825..1f5414e95b 100644
--- a/docs/topics/http/middleware.txt
+++ b/docs/topics/http/middleware.txt
@@ -16,18 +16,128 @@ how to write your own middleware. Django ships with some built-in middleware
you can use right out of the box. They're documented in the :doc:`built-in
middleware reference </ref/middleware>`.
+.. versionchanged:: 1.10
+
+ A new style of middleware was introduced for use with the new
+ :setting:`MIDDLEWARE` setting. If you're using the old
+ :setting:`MIDDLEWARE_CLASSES` setting, you'll need to :ref:`adapt old,
+ custom middleware <upgrading-middleware>` before using the new setting.
+ This document describes new-style middleware. Refer to this page in older
+ versions of the documentation for a description of how old-style middleware
+ works.
+
+Writing your own middleware
+===========================
+
+A middleware factory is a callable that takes a ``get_response`` callable and
+returns a middleware. A middleware is a callable that takes a request and
+returns a response, just like a view.
+
+A middleware can be written as a function that looks like this::
+
+ def simple_middleware(get_response):
+ # One-time configuration and initialization.
+
+ def middleware(request):
+ # Code to be executed for each request before
+ # the view is called.
+
+ try:
+ response = get_response(request)
+ except Exception as e:
+ # Code to handle an exception that wasn't caught
+ # further up the chain, if desired.
+ ...
+
+ # Code to be executed for each request/response after
+ # the view is called.
+
+ return response
+
+ return middleware
+
+Or it can be written as a class with a ``__call__()`` method, like this::
+
+ class SimpleMiddleware(object):
+ def __init__(self, get_response):
+ self.get_response = get_response
+ # One-time configuration and initialization.
+
+ def __call__(self, request):
+ # Code to be executed for each request before
+ # the view is called.
+
+ try:
+ response = self.get_response(request)
+ except Exception as e:
+ # Code to handle an exception that wasn't caught
+ # further up the chain, if desired.
+ ...
+
+ # Code to be executed for each request/response after
+ # the view is called.
+
+ return response
+
+In both examples, the ``try``/``except`` isn't required if the middleware
+doesn't need to handle any exceptions. If it is included, it should probably
+catch something more specific than ``Exception``.
+
+The ``get_response`` callable provided by Django might be the actual view (if
+this is the last listed middleware) or it might be the next middleware in the
+chain. The current middleware doesn't need to know or care what exactly it is,
+just that it represents whatever comes next.
+
+The above is a slight simplification -- the ``get_response`` callable for the
+last middleware in the chain won't be the actual view but rather a wrapper
+method from the handler which takes care of applying :ref:`view middleware
+<view-middleware>`, calling the view with appropriate URL arguments, and
+applying :ref:`template-response <template-response-middleware>` middleware.
+
+Middleware can live anywhere on your Python path.
+
+``__init__(get_response)``
+--------------------------
+
+Middleware classes must accept a ``get_response`` argument. You can also
+initialize some global state for the middleware. Keep in mind a couple of
+caveats:
+
+* Django initializes your middleware with only the ``get_response`` argument,
+ so you can't define ``__init__()`` as requiring any other arguments.
+
+* Unlike the ``__call__()`` method which get called once per request,
+ ``__init__()`` is called only *once*, when the Web server starts.
+
+.. versionchanged:: 1.10
+
+ In older versions, ``__init__`` was not called until the Web server
+ responded to its first request.
+
+ If you want to allow your middleware to be used in Django 1.9 and earlier,
+ make ``get_response`` an optional argument (``get_response=None``).
+
+Marking middleware as unused
+----------------------------
+
+It's sometimes useful to determine at startup time whether a piece of
+middleware should be used. In these cases, your middleware's ``__init__()``
+method may raise :exc:`~django.core.exceptions.MiddlewareNotUsed`. Django will
+then remove that middleware from the middleware process and log a debug message
+to the :ref:`django-request-logger` logger when :setting:`DEBUG` is ``True``.
+
Activating middleware
=====================
-To activate a middleware component, add it to the
-:setting:`MIDDLEWARE_CLASSES` list in your Django settings.
+To activate a middleware component, add it to the :setting:`MIDDLEWARE` list in
+your Django settings.
-In :setting:`MIDDLEWARE_CLASSES`, each middleware component is represented by
-a string: the full Python path to the middleware's class name. For example,
+In :setting:`MIDDLEWARE`, each middleware component is represented by a string:
+the full Python path to the middleware's class or function name. For example,
here's the default value created by :djadmin:`django-admin startproject
<startproject>`::
- MIDDLEWARE_CLASSES = [
+ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
@@ -37,13 +147,12 @@ here's the default value created by :djadmin:`django-admin startproject
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
-A Django installation doesn't require any middleware —
-:setting:`MIDDLEWARE_CLASSES` can be empty, if you'd like — but it's strongly
-suggested that you at least use
+A Django installation doesn't require any middleware — :setting:`MIDDLEWARE`
+can be empty, if you'd like — but it's strongly suggested that you at least use
:class:`~django.middleware.common.CommonMiddleware`.
-The order in :setting:`MIDDLEWARE_CLASSES` matters because a middleware can
-depend on other middleware. For instance,
+The order in :setting:`MIDDLEWARE` matters because a middleware can depend on
+other middleware. For instance,
:class:`~django.contrib.auth.middleware.AuthenticationMiddleware` stores the
authenticated user in the session; therefore, it must run after
:class:`~django.contrib.sessions.middleware.SessionMiddleware`. See
@@ -54,55 +163,21 @@ Hooks and application order
===========================
During the request phase, before calling the view, Django applies middleware
-in the order it's defined in :setting:`MIDDLEWARE_CLASSES`, top-down. Two
-hooks are available:
-
-* :meth:`process_request`
-* :meth:`process_view`
-
-During the response phase, after calling the view, middleware are applied in
-reverse order, from the bottom up. Three hooks are available:
-
-* :meth:`process_exception` (only if the view raised an exception)
-* :meth:`process_template_response` (only for template responses)
-* :meth:`process_response`
+in the order it's defined in :setting:`MIDDLEWARE`, top-down. You can think of
+it like an onion: each middleware class is a "layer" that wraps the view.
-.. image:: _images/middleware.*
- :alt: middleware application order
- :width: 481
- :height: 409
+Middleware see only the changes made by middleware that run before it. A
+middleware (and the view) is skipped entirely if a preceding middleware
+short-circuits by returning a response without ever calling ``get_response``.
+That response will only pass through the middleware that have already run.
-If you prefer, you can also think of it like an onion: each middleware class
-is a "layer" that wraps the view.
-
-The behavior of each hook is described below.
-
-Writing your own middleware
-===========================
+Similarly, a middleware that sees the request on the way in and doesn't return
+a response is guaranteed that it will always see the response on the way back
+out. If the middleware also wants to see any uncaught exception on the way out,
+it can wrap its call to ``get_response()`` in a ``try``/``except``.
-Writing your own middleware is easy. Each middleware component is a single
-Python class that defines one or more of the following methods:
-
-.. _request-middleware:
-
-``process_request()``
----------------------
-
-.. method:: process_request(request)
-
-``request`` is an :class:`~django.http.HttpRequest` object.
-
-``process_request()`` is called on each request, before Django decides which
-view to execute.
-
-It should return either ``None`` or an :class:`~django.http.HttpResponse`
-object. If it returns ``None``, Django will continue processing this request,
-executing any other ``process_request()`` middleware, then, ``process_view()``
-middleware, and finally, the appropriate view. If it returns an
-:class:`~django.http.HttpResponse` object, Django won't bother calling any
-other request, view or exception middleware, or the appropriate view; it'll
-apply response middleware to that :class:`~django.http.HttpResponse`, and
-return the result.
+Besides the middleware pattern described earlier, you can add two other methods
+to class-based middleware:
.. _view-middleware:
@@ -125,14 +200,13 @@ It should return either ``None`` or an :class:`~django.http.HttpResponse`
object. If it returns ``None``, Django will continue processing this request,
executing any other ``process_view()`` middleware and, then, the appropriate
view. If it returns an :class:`~django.http.HttpResponse` object, Django won't
-bother calling any other view or exception middleware, or the appropriate
-view; it'll apply response middleware to that
-:class:`~django.http.HttpResponse`, and return the result.
+bother calling the appropriate view; it'll apply response middleware to that
+:class:`~django.http.HttpResponse` and return the result.
.. note::
Accessing :attr:`request.POST <django.http.HttpRequest.POST>` inside
- middleware from ``process_request`` or ``process_view`` will prevent any
+ middleware before the view runs or in ``process_view()`` will prevent any
view running after the middleware from being able to :ref:`modify the
upload handlers for the request <modifying_upload_handlers_on_the_fly>`,
and should normally be avoided.
@@ -170,41 +244,8 @@ called.
Middleware are run in reverse order during the response phase, which
includes ``process_template_response()``.
-.. _response-middleware:
-
-``process_response()``
-----------------------
-
-.. method:: process_response(request, response)
-
-``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is
-the :class:`~django.http.HttpResponse` or
-:class:`~django.http.StreamingHttpResponse` object returned by a Django view
-or by a middleware.
-
-``process_response()`` is called on all responses before they're returned to
-the browser.
-
-It must return an :class:`~django.http.HttpResponse` or
-:class:`~django.http.StreamingHttpResponse` object. It could alter the given
-``response``, or it could create and return a brand-new
-:class:`~django.http.HttpResponse` or
-:class:`~django.http.StreamingHttpResponse`.
-
-Unlike the ``process_request()`` and ``process_view()`` methods, the
-``process_response()`` method is always called, even if the
-``process_request()`` and ``process_view()`` methods of the same middleware
-class were skipped (because an earlier middleware method returned an
-:class:`~django.http.HttpResponse`). In particular, this means that your
-``process_response()`` method cannot rely on setup done in
-``process_request()``.
-
-Finally, remember that during the response phase, middleware are applied in
-reverse order, from the bottom up. This means classes defined at the end of
-:setting:`MIDDLEWARE_CLASSES` will be run first.
-
Dealing with streaming responses
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+================================
Unlike :class:`~django.http.HttpResponse`,
:class:`~django.http.StreamingHttpResponse` does not have a ``content``
@@ -229,66 +270,62 @@ must test for streaming responses and adjust their behavior accordingly::
.. _exception-middleware:
-``process_exception()``
------------------------
+Exception middleware
+====================
-.. method:: process_exception(request, exception)
+A middleware that does some custom exception handling might looks like this::
-``request`` is an :class:`~django.http.HttpRequest` object. ``exception`` is an
-``Exception`` object raised by the view function.
+ class ExceptionMiddleware(object):
+ def __init__(self, get_response):
+ self.get_response = get_response
-Django calls ``process_exception()`` when a view raises an exception.
-``process_exception()`` should return either ``None`` or an
-:class:`~django.http.HttpResponse` object. If it returns an
-:class:`~django.http.HttpResponse` object, the template response and response
-middleware will be applied, and the resulting response returned to the
-browser. Otherwise, default exception handling kicks in.
+ def __call__(self, request):
+ try:
+ response = self.get_response(request)
+ except Exception as e:
+ # Do something with the exception and possibly reraise it
+ # unless you wish to silence it.
+ ...
+ return response
-Again, middleware are run in reverse order during the response phase, which
-includes ``process_exception``. If an exception middleware returns a response,
-the middleware classes above that middleware will not be called at all.
+Middleware that wants to do something for all exception responses, an HTTP 404
+for example, need to both catch the appropriate exception (e.g. ``Http404``)
+and look for regular responses with the status code of interest. You can
+subclass :class:`~django.middleware.exception.ExceptionMiddleware` if you want
+to transform exceptions into the appropriate response.
-``__init__()``
---------------
+.. _upgrading-middleware:
-Most middleware classes won't need an initializer since middleware classes are
-essentially placeholders for the ``process_*`` methods. If you do need some
-global state you may use ``__init__`` to set up. However, keep in mind a couple
-of caveats:
+Upgrading pre-Django 1.10-style middleware
+==========================================
-* Django initializes your middleware without any arguments, so you can't
- define ``__init__`` as requiring any arguments.
-
-* Unlike the ``process_*`` methods which get called once per request,
- ``__init__`` gets called only *once*, when the Web server starts.
-
-.. versionchanged:: 1.10
-
- In older versions, ``__init__`` was not called until the Web server
- responded to its first request.
-
-Marking middleware as unused
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. class:: django.utils.deprecation.MiddlewareMixin
+ :module:
-It's sometimes useful to determine at run-time whether a piece of middleware
-should be used. In these cases, your middleware's ``__init__`` method may
-raise :exc:`django.core.exceptions.MiddlewareNotUsed`. Django will then remove
-that piece of middleware from the middleware process and a debug message will
-be logged to the ``django.request`` logger when :setting:`DEBUG` is set to
-``True``.
+Django provides ``django.utils.deprecation.MiddlewareMixin`` to ease providing
+the existing built-in middleware in both new-style and old-style forms and to
+ease similar conversions of third-party middleware.
-Guidelines
-----------
+In most cases, this mixin will be sufficient to convert a middleware with
+sufficient backwards-compatibility; the new short-circuiting semantics will be
+harmless or even beneficial to the existing middleware.
-* Middleware classes don't have to subclass anything.
+In a few cases, a middleware class may need more invasive changes to adjust to
+the new semantics.
-* The middleware class can live anywhere on your Python path. All Django
- cares about is that the :setting:`MIDDLEWARE_CLASSES` setting includes
- the path to it.
+For example, in the current request-handling logic, the handler transforms any
+exception that passes through all ``process_exception`` middleware uncaught
+into a response with appropriate status code (e.g. 404, 403, 400, or 500), and
+then passes that response through the full chain of ``process_response``
+middleware.
-* Feel free to look at :doc:`Django's available middleware
- </ref/middleware>` for examples.
+In new-style middleware, a given middleware only gets one shot at a given
+response or uncaught exception "on the way out," and will see either a returned
+response or an uncaught exception, but not both.
-* If you write a middleware component that you think would be useful to
- other people, contribute to the community! :doc:`Let us know
- </internals/contributing/index>`, and we'll consider adding it to Django.
+This means that certain middleware which want to do something with all 404
+responses (for example, the ``RedirectFallbackMiddleware`` and
+``FlatpageFallbackMiddleware`` in ``django.contrib.redirects`` and
+``django.contrib.flatpages``) now need to watch out for both a 404 response
+and an uncaught ``Http404`` exception. They do this by subclassing
+:class:`~django.middleware.exception.ExceptionMiddleware`.
diff --git a/docs/topics/http/sessions.txt b/docs/topics/http/sessions.txt
index 34a1b28b73..1a948397ae 100644
--- a/docs/topics/http/sessions.txt
+++ b/docs/topics/http/sessions.txt
@@ -18,13 +18,13 @@ Sessions are implemented via a piece of :doc:`middleware </ref/middleware>`.
To enable session functionality, do the following:
-* Edit the :setting:`MIDDLEWARE_CLASSES` setting and make sure
- it contains ``'django.contrib.sessions.middleware.SessionMiddleware'``.
- The default ``settings.py`` created by ``django-admin startproject``
- has ``SessionMiddleware`` activated.
+* Edit the :setting:`MIDDLEWARE` setting and make sure it contains
+ ``'django.contrib.sessions.middleware.SessionMiddleware'``. The default
+ ``settings.py`` created by ``django-admin startproject`` has
+ ``SessionMiddleware`` activated.
If you don't want to use sessions, you might as well remove the
-``SessionMiddleware`` line from :setting:`MIDDLEWARE_CLASSES` and
+``SessionMiddleware`` line from :setting:`MIDDLEWARE` and
``'django.contrib.sessions'`` from your :setting:`INSTALLED_APPS`.
It'll save you a small bit of overhead.
diff --git a/docs/topics/http/urls.txt b/docs/topics/http/urls.txt
index 81dc4a0d94..ae5b714726 100644
--- a/docs/topics/http/urls.txt
+++ b/docs/topics/http/urls.txt
@@ -41,8 +41,8 @@ algorithm the system follows to determine which Python code to execute:
1. Django determines the root URLconf module to use. Ordinarily,
this is the value of the :setting:`ROOT_URLCONF` setting, but if the incoming
``HttpRequest`` object has a :attr:`~django.http.HttpRequest.urlconf`
- attribute (set by middleware :ref:`request processing <request-middleware>`),
- its value will be used in place of the :setting:`ROOT_URLCONF` setting.
+ attribute (set by middleware), its value will be used in place of the
+ :setting:`ROOT_URLCONF` setting.
2. Django loads that Python module and looks for the variable
``urlpatterns``. This should be a Python list of :func:`django.conf.urls.url`
diff --git a/docs/topics/i18n/timezones.txt b/docs/topics/i18n/timezones.txt
index 8ea63f2908..674edc1a19 100644
--- a/docs/topics/i18n/timezones.txt
+++ b/docs/topics/i18n/timezones.txt
@@ -175,13 +175,14 @@ the most likely choices.
Here's an example that stores the current timezone in the session. (It skips
error handling entirely for the sake of simplicity.)
-Add the following middleware to :setting:`MIDDLEWARE_CLASSES`::
+Add the following middleware to :setting:`MIDDLEWARE`::
import pytz
from django.utils import timezone
+ from django.django.utils.deprecation import MiddlewareMixin
- class TimezoneMiddleware(object):
+ class TimezoneMiddleware(MiddlewareMixin):
def process_request(self, request):
tzname = request.session.get('django_timezone')
if tzname:
diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt
index 43184a13a1..3f13021bc8 100644
--- a/docs/topics/i18n/translation.txt
+++ b/docs/topics/i18n/translation.txt
@@ -38,7 +38,7 @@ make some optimizations so as not to load the internationalization machinery.
.. note::
Make sure you've activated translation for your project (the fastest way is
- to check if :setting:`MIDDLEWARE_CLASSES` includes
+ to check if :setting:`MIDDLEWARE` includes
:mod:`django.middleware.locale.LocaleMiddleware`). If you haven't yet,
see :ref:`how-django-discovers-language-preference`.
@@ -1422,7 +1422,7 @@ Django provides two mechanisms to internationalize URL patterns:
Using either one of these features requires that an active language be set
for each request; in other words, you need to have
:class:`django.middleware.locale.LocaleMiddleware` in your
- :setting:`MIDDLEWARE_CLASSES` setting.
+ :setting:`MIDDLEWARE` setting.
Language prefix in URL patterns
-------------------------------
@@ -2065,8 +2065,8 @@ prefer, then you also need to use the ``LocaleMiddleware``.
It customizes content for each user.
To use ``LocaleMiddleware``, add ``'django.middleware.locale.LocaleMiddleware'``
-to your :setting:`MIDDLEWARE_CLASSES` setting. Because middleware order
-matters, you should follow these guidelines:
+to your :setting:`MIDDLEWARE` setting. Because middleware order matters, follow
+these guidelines:
* Make sure it's one of the first middlewares installed.
* It should come after ``SessionMiddleware``, because ``LocaleMiddleware``
@@ -2075,9 +2075,9 @@ matters, you should follow these guidelines:
to resolve the requested URL.
* If you use ``CacheMiddleware``, put ``LocaleMiddleware`` after it.
-For example, your :setting:`MIDDLEWARE_CLASSES` might look like this::
+For example, your :setting:`MIDDLEWARE` might look like this::
- MIDDLEWARE_CLASSES = [
+ MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
diff --git a/docs/topics/testing/tools.txt b/docs/topics/testing/tools.txt
index 8db06c15a3..d2ef214c36 100644
--- a/docs/topics/testing/tools.txt
+++ b/docs/topics/testing/tools.txt
@@ -1182,7 +1182,7 @@ easy::
class MiddlewareTestCase(TestCase):
def test_cache_middleware(self):
- with self.modify_settings(MIDDLEWARE_CLASSES={
+ with self.modify_settings(MIDDLEWARE={
'append': 'django.middleware.cache.FetchFromCacheMiddleware',
'prepend': 'django.middleware.cache.UpdateCacheMiddleware',
'remove': [
@@ -1233,7 +1233,7 @@ decorator::
class MiddlewareTestCase(TestCase):
- @modify_settings(MIDDLEWARE_CLASSES={
+ @modify_settings(MIDDLEWARE={
'append': 'django.middleware.cache.FetchFromCacheMiddleware',
'prepend': 'django.middleware.cache.UpdateCacheMiddleware',
})
@@ -1245,7 +1245,7 @@ The decorator can also be applied to test case classes::
from django.test import TestCase, modify_settings
- @modify_settings(MIDDLEWARE_CLASSES={
+ @modify_settings(MIDDLEWARE={
'append': 'django.middleware.cache.FetchFromCacheMiddleware',
'prepend': 'django.middleware.cache.UpdateCacheMiddleware',
})
diff --git a/tests/auth_tests/settings.py b/tests/auth_tests/settings.py
index 7da6144d4b..8c295387c4 100644
--- a/tests/auth_tests/settings.py
+++ b/tests/auth_tests/settings.py
@@ -2,7 +2,7 @@ import os
from django.utils._os import upath
-AUTH_MIDDLEWARE_CLASSES = [
+AUTH_MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
]
diff --git a/tests/auth_tests/test_context_processors.py b/tests/auth_tests/test_context_processors.py
index 3a8d800c74..d1db63c7b2 100644
--- a/tests/auth_tests/test_context_processors.py
+++ b/tests/auth_tests/test_context_processors.py
@@ -5,7 +5,7 @@ from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from django.test import SimpleTestCase, TestCase, override_settings
-from .settings import AUTH_MIDDLEWARE_CLASSES, AUTH_TEMPLATES
+from .settings import AUTH_MIDDLEWARE, AUTH_TEMPLATES
class MockUser(object):
@@ -67,7 +67,7 @@ class AuthContextProcessorTests(TestCase):
def setUpTestData(cls):
cls.superuser = User.objects.create_superuser(username='super', password='secret', email='super@example.com')
- @override_settings(MIDDLEWARE_CLASSES=AUTH_MIDDLEWARE_CLASSES)
+ @override_settings(MIDDLEWARE=AUTH_MIDDLEWARE)
def test_session_not_accessed(self):
"""
Tests that the session is not accessed simply by including
@@ -76,7 +76,12 @@ class AuthContextProcessorTests(TestCase):
response = self.client.get('/auth_processor_no_attr_access/')
self.assertContains(response, "Session not accessed")
- @override_settings(MIDDLEWARE_CLASSES=AUTH_MIDDLEWARE_CLASSES)
+ @override_settings(MIDDLEWARE_CLASSES=AUTH_MIDDLEWARE, MIDDLEWARE=None)
+ def test_session_not_accessed_middleware_classes(self):
+ response = self.client.get('/auth_processor_no_attr_access/')
+ self.assertContains(response, "Session not accessed")
+
+ @override_settings(MIDDLEWARE=AUTH_MIDDLEWARE)
def test_session_is_accessed(self):
"""
Tests that the session is accessed if the auth context processor
@@ -85,6 +90,11 @@ class AuthContextProcessorTests(TestCase):
response = self.client.get('/auth_processor_attr_access/')
self.assertContains(response, "Session accessed")
+ @override_settings(MIDDLEWARE_CLASSES=AUTH_MIDDLEWARE, MIDDLEWARE=None)
+ def test_session_is_accessed_middleware_classes(self):
+ response = self.client.get('/auth_processor_attr_access/')
+ self.assertContains(response, "Session accessed")
+
def test_perms_attrs(self):
u = User.objects.create_user(username='normal', password='secret')
u.user_permissions.add(
diff --git a/tests/auth_tests/test_remote_user.py b/tests/auth_tests/test_remote_user.py
index 3d77ea3b89..1cb7666a49 100644
--- a/tests/auth_tests/test_remote_user.py
+++ b/tests/auth_tests/test_remote_user.py
@@ -23,7 +23,7 @@ class RemoteUserTest(TestCase):
def setUp(self):
self.patched_settings = modify_settings(
AUTHENTICATION_BACKENDS={'append': self.backend},
- MIDDLEWARE_CLASSES={'append': self.middleware},
+ MIDDLEWARE={'append': self.middleware},
)
self.patched_settings.enable()
@@ -151,6 +151,21 @@ class RemoteUserTest(TestCase):
self.assertTrue(response.context['user'].is_anonymous)
+@override_settings(MIDDLEWARE=None)
+class RemoteUserTestMiddlewareClasses(RemoteUserTest):
+
+ def setUp(self):
+ self.patched_settings = modify_settings(
+ AUTHENTICATION_BACKENDS={'append': self.backend},
+ MIDDLEWARE_CLASSES={'append': [
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ self.middleware,
+ ]},
+ )
+ self.patched_settings.enable()
+
+
class RemoteUserNoCreateBackend(RemoteUserBackend):
"""Backend that doesn't create unknown users."""
create_unknown_user = False
diff --git a/tests/check_framework/test_security.py b/tests/check_framework/test_security.py
index 34254b66d5..b4591030f5 100644
--- a/tests/check_framework/test_security.py
+++ b/tests/check_framework/test_security.py
@@ -1,5 +1,6 @@
from django.conf import settings
from django.core.checks.security import base, csrf, sessions
+from django.core.checks.utils import patch_middleware_message
from django.test import SimpleTestCase
from django.test.utils import override_settings
@@ -13,7 +14,7 @@ class CheckSessionCookieSecureTest(SimpleTestCase):
@override_settings(
SESSION_COOKIE_SECURE=False,
INSTALLED_APPS=["django.contrib.sessions"],
- MIDDLEWARE_CLASSES=[])
+ MIDDLEWARE=[])
def test_session_cookie_secure_with_installed_app(self):
"""
Warn if SESSION_COOKIE_SECURE is off and "django.contrib.sessions" is
@@ -23,20 +24,36 @@ class CheckSessionCookieSecureTest(SimpleTestCase):
@override_settings(
SESSION_COOKIE_SECURE=False,
+ INSTALLED_APPS=["django.contrib.sessions"],
+ MIDDLEWARE=None,
+ MIDDLEWARE_CLASSES=[])
+ def test_session_cookie_secure_with_installed_app_middleware_classes(self):
+ self.assertEqual(self.func(None), [sessions.W010])
+
+ @override_settings(
+ SESSION_COOKIE_SECURE=False,
INSTALLED_APPS=[],
- MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"])
+ MIDDLEWARE=["django.contrib.sessions.middleware.SessionMiddleware"])
def test_session_cookie_secure_with_middleware(self):
"""
Warn if SESSION_COOKIE_SECURE is off and
"django.contrib.sessions.middleware.SessionMiddleware" is in
- MIDDLEWARE_CLASSES.
+ MIDDLEWARE.
"""
self.assertEqual(self.func(None), [sessions.W011])
@override_settings(
SESSION_COOKIE_SECURE=False,
- INSTALLED_APPS=["django.contrib.sessions"],
+ INSTALLED_APPS=[],
+ MIDDLEWARE=None,
MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"])
+ def test_session_cookie_secure_with_middleware_middleware_classes(self):
+ self.assertEqual(self.func(None), [patch_middleware_message(sessions.W011)])
+
+ @override_settings(
+ SESSION_COOKIE_SECURE=False,
+ INSTALLED_APPS=["django.contrib.sessions"],
+ MIDDLEWARE=["django.contrib.sessions.middleware.SessionMiddleware"])
def test_session_cookie_secure_both(self):
"""
If SESSION_COOKIE_SECURE is off and we find both the session app and
@@ -45,9 +62,17 @@ class CheckSessionCookieSecureTest(SimpleTestCase):
self.assertEqual(self.func(None), [sessions.W012])
@override_settings(
- SESSION_COOKIE_SECURE=True,
+ SESSION_COOKIE_SECURE=False,
INSTALLED_APPS=["django.contrib.sessions"],
+ MIDDLEWARE=None,
MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"])
+ def test_session_cookie_secure_both_middleware_classes(self):
+ self.assertEqual(self.func(None), [sessions.W012])
+
+ @override_settings(
+ SESSION_COOKIE_SECURE=True,
+ INSTALLED_APPS=["django.contrib.sessions"],
+ MIDDLEWARE=["django.contrib.sessions.middleware.SessionMiddleware"])
def test_session_cookie_secure_true(self):
"""
If SESSION_COOKIE_SECURE is on, there's no warning about it.
@@ -64,7 +89,7 @@ class CheckSessionCookieHttpOnlyTest(SimpleTestCase):
@override_settings(
SESSION_COOKIE_HTTPONLY=False,
INSTALLED_APPS=["django.contrib.sessions"],
- MIDDLEWARE_CLASSES=[])
+ MIDDLEWARE=[])
def test_session_cookie_httponly_with_installed_app(self):
"""
Warn if SESSION_COOKIE_HTTPONLY is off and "django.contrib.sessions"
@@ -75,19 +100,19 @@ class CheckSessionCookieHttpOnlyTest(SimpleTestCase):
@override_settings(
SESSION_COOKIE_HTTPONLY=False,
INSTALLED_APPS=[],
- MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"])
+ MIDDLEWARE=["django.contrib.sessions.middleware.SessionMiddleware"])
def test_session_cookie_httponly_with_middleware(self):
"""
Warn if SESSION_COOKIE_HTTPONLY is off and
"django.contrib.sessions.middleware.SessionMiddleware" is in
- MIDDLEWARE_CLASSES.
+ MIDDLEWARE.
"""
self.assertEqual(self.func(None), [sessions.W014])
@override_settings(
SESSION_COOKIE_HTTPONLY=False,
INSTALLED_APPS=["django.contrib.sessions"],
- MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"])
+ MIDDLEWARE=["django.contrib.sessions.middleware.SessionMiddleware"])
def test_session_cookie_httponly_both(self):
"""
If SESSION_COOKIE_HTTPONLY is off and we find both the session app and
@@ -98,7 +123,7 @@ class CheckSessionCookieHttpOnlyTest(SimpleTestCase):
@override_settings(
SESSION_COOKIE_HTTPONLY=True,
INSTALLED_APPS=["django.contrib.sessions"],
- MIDDLEWARE_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"])
+ MIDDLEWARE=["django.contrib.sessions.middleware.SessionMiddleware"])
def test_session_cookie_httponly_true(self):
"""
If SESSION_COOKIE_HTTPONLY is on, there's no warning about it.
@@ -112,15 +137,15 @@ class CheckCSRFMiddlewareTest(SimpleTestCase):
from django.core.checks.security.csrf import check_csrf_middleware
return check_csrf_middleware
- @override_settings(MIDDLEWARE_CLASSES=[])
+ @override_settings(MIDDLEWARE=[], MIDDLEWARE_CLASSES=[])
def test_no_csrf_middleware(self):
"""
- Warn if CsrfViewMiddleware isn't in MIDDLEWARE_CLASSES.
+ Warn if CsrfViewMiddleware isn't in MIDDLEWARE.
"""
self.assertEqual(self.func(None), [csrf.W003])
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.csrf.CsrfViewMiddleware"])
+ MIDDLEWARE=["django.middleware.csrf.CsrfViewMiddleware"])
def test_with_csrf_middleware(self):
self.assertEqual(self.func(None), [])
@@ -132,25 +157,25 @@ class CheckCSRFCookieSecureTest(SimpleTestCase):
return check_csrf_cookie_secure
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.csrf.CsrfViewMiddleware"],
+ MIDDLEWARE=["django.middleware.csrf.CsrfViewMiddleware"],
CSRF_COOKIE_SECURE=False)
def test_with_csrf_cookie_secure_false(self):
"""
- Warn if CsrfViewMiddleware is in MIDDLEWARE_CLASSES but
+ Warn if CsrfViewMiddleware is in MIDDLEWARE but
CSRF_COOKIE_SECURE isn't True.
"""
self.assertEqual(self.func(None), [csrf.W016])
- @override_settings(MIDDLEWARE_CLASSES=[], CSRF_COOKIE_SECURE=False)
+ @override_settings(MIDDLEWARE=[], MIDDLEWARE_CLASSES=[], CSRF_COOKIE_SECURE=False)
def test_with_csrf_cookie_secure_false_no_middleware(self):
"""
- No warning if CsrfViewMiddleware isn't in MIDDLEWARE_CLASSES, even if
+ No warning if CsrfViewMiddleware isn't in MIDDLEWARE, even if
CSRF_COOKIE_SECURE is False.
"""
self.assertEqual(self.func(None), [])
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.csrf.CsrfViewMiddleware"],
+ MIDDLEWARE=["django.middleware.csrf.CsrfViewMiddleware"],
CSRF_COOKIE_SECURE=True)
def test_with_csrf_cookie_secure_true(self):
self.assertEqual(self.func(None), [])
@@ -163,25 +188,25 @@ class CheckCSRFCookieHttpOnlyTest(SimpleTestCase):
return check_csrf_cookie_httponly
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.csrf.CsrfViewMiddleware"],
+ MIDDLEWARE=["django.middleware.csrf.CsrfViewMiddleware"],
CSRF_COOKIE_HTTPONLY=False)
def test_with_csrf_cookie_httponly_false(self):
"""
- Warn if CsrfViewMiddleware is in MIDDLEWARE_CLASSES but
+ Warn if CsrfViewMiddleware is in MIDDLEWARE but
CSRF_COOKIE_HTTPONLY isn't True.
"""
self.assertEqual(self.func(None), [csrf.W017])
- @override_settings(MIDDLEWARE_CLASSES=[], CSRF_COOKIE_HTTPONLY=False)
+ @override_settings(MIDDLEWARE=[], MIDDLEWARE_CLASSES=[], CSRF_COOKIE_HTTPONLY=False)
def test_with_csrf_cookie_httponly_false_no_middleware(self):
"""
- No warning if CsrfViewMiddleware isn't in MIDDLEWARE_CLASSES, even if
+ No warning if CsrfViewMiddleware isn't in MIDDLEWARE, even if
CSRF_COOKIE_HTTPONLY is False.
"""
self.assertEqual(self.func(None), [])
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.csrf.CsrfViewMiddleware"],
+ MIDDLEWARE=["django.middleware.csrf.CsrfViewMiddleware"],
CSRF_COOKIE_HTTPONLY=True)
def test_with_csrf_cookie_httponly_true(self):
self.assertEqual(self.func(None), [])
@@ -193,15 +218,15 @@ class CheckSecurityMiddlewareTest(SimpleTestCase):
from django.core.checks.security.base import check_security_middleware
return check_security_middleware
- @override_settings(MIDDLEWARE_CLASSES=[])
+ @override_settings(MIDDLEWARE=[])
def test_no_security_middleware(self):
"""
- Warn if SecurityMiddleware isn't in MIDDLEWARE_CLASSES.
+ Warn if SecurityMiddleware isn't in MIDDLEWARE.
"""
self.assertEqual(self.func(None), [base.W001])
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"])
+ MIDDLEWARE=["django.middleware.security.SecurityMiddleware"])
def test_with_security_middleware(self):
self.assertEqual(self.func(None), [])
@@ -213,7 +238,7 @@ class CheckStrictTransportSecurityTest(SimpleTestCase):
return check_sts
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_HSTS_SECONDS=0)
def test_no_sts(self):
"""
@@ -222,7 +247,7 @@ class CheckStrictTransportSecurityTest(SimpleTestCase):
self.assertEqual(self.func(None), [base.W004])
@override_settings(
- MIDDLEWARE_CLASSES=[],
+ MIDDLEWARE=[],
SECURE_HSTS_SECONDS=0)
def test_no_sts_no_middleware(self):
"""
@@ -232,7 +257,7 @@ class CheckStrictTransportSecurityTest(SimpleTestCase):
self.assertEqual(self.func(None), [])
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_HSTS_SECONDS=3600)
def test_with_sts(self):
self.assertEqual(self.func(None), [])
@@ -245,7 +270,7 @@ class CheckStrictTransportSecuritySubdomainsTest(SimpleTestCase):
return check_sts_include_subdomains
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_HSTS_INCLUDE_SUBDOMAINS=False,
SECURE_HSTS_SECONDS=3600)
def test_no_sts_subdomains(self):
@@ -255,7 +280,7 @@ class CheckStrictTransportSecuritySubdomainsTest(SimpleTestCase):
self.assertEqual(self.func(None), [base.W005])
@override_settings(
- MIDDLEWARE_CLASSES=[],
+ MIDDLEWARE=[],
SECURE_HSTS_INCLUDE_SUBDOMAINS=False,
SECURE_HSTS_SECONDS=3600)
def test_no_sts_subdomains_no_middleware(self):
@@ -265,7 +290,7 @@ class CheckStrictTransportSecuritySubdomainsTest(SimpleTestCase):
self.assertEqual(self.func(None), [])
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_SSL_REDIRECT=False,
SECURE_HSTS_SECONDS=None)
def test_no_sts_subdomains_no_seconds(self):
@@ -275,7 +300,7 @@ class CheckStrictTransportSecuritySubdomainsTest(SimpleTestCase):
self.assertEqual(self.func(None), [])
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_HSTS_INCLUDE_SUBDOMAINS=True,
SECURE_HSTS_SECONDS=3600)
def test_with_sts_subdomains(self):
@@ -288,14 +313,14 @@ class CheckXFrameOptionsMiddlewareTest(SimpleTestCase):
from django.core.checks.security.base import check_xframe_options_middleware
return check_xframe_options_middleware
- @override_settings(MIDDLEWARE_CLASSES=[])
+ @override_settings(MIDDLEWARE=[])
def test_middleware_not_installed(self):
"""
- Warn if XFrameOptionsMiddleware isn't in MIDDLEWARE_CLASSES.
+ Warn if XFrameOptionsMiddleware isn't in MIDDLEWARE.
"""
self.assertEqual(self.func(None), [base.W002])
- @override_settings(MIDDLEWARE_CLASSES=["django.middleware.clickjacking.XFrameOptionsMiddleware"])
+ @override_settings(MIDDLEWARE=["django.middleware.clickjacking.XFrameOptionsMiddleware"])
def test_middleware_installed(self):
self.assertEqual(self.func(None), [])
@@ -307,26 +332,26 @@ class CheckXFrameOptionsDenyTest(SimpleTestCase):
return check_xframe_deny
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.clickjacking.XFrameOptionsMiddleware"],
+ MIDDLEWARE=["django.middleware.clickjacking.XFrameOptionsMiddleware"],
X_FRAME_OPTIONS='SAMEORIGIN',
)
def test_x_frame_options_not_deny(self):
"""
- Warn if XFrameOptionsMiddleware is in MIDDLEWARE_CLASSES but
+ Warn if XFrameOptionsMiddleware is in MIDDLEWARE but
X_FRAME_OPTIONS isn't 'DENY'.
"""
self.assertEqual(self.func(None), [base.W019])
- @override_settings(MIDDLEWARE_CLASSES=[], X_FRAME_OPTIONS='SAMEORIGIN')
+ @override_settings(MIDDLEWARE=[], X_FRAME_OPTIONS='SAMEORIGIN')
def test_middleware_not_installed(self):
"""
- No error if XFrameOptionsMiddleware isn't in MIDDLEWARE_CLASSES even if
+ No error if XFrameOptionsMiddleware isn't in MIDDLEWARE even if
X_FRAME_OPTIONS isn't 'DENY'.
"""
self.assertEqual(self.func(None), [])
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.clickjacking.XFrameOptionsMiddleware"],
+ MIDDLEWARE=["django.middleware.clickjacking.XFrameOptionsMiddleware"],
X_FRAME_OPTIONS='DENY',
)
def test_xframe_deny(self):
@@ -340,7 +365,7 @@ class CheckContentTypeNosniffTest(SimpleTestCase):
return check_content_type_nosniff
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_CONTENT_TYPE_NOSNIFF=False)
def test_no_content_type_nosniff(self):
"""
@@ -349,17 +374,17 @@ class CheckContentTypeNosniffTest(SimpleTestCase):
self.assertEqual(self.func(None), [base.W006])
@override_settings(
- MIDDLEWARE_CLASSES=[],
+ MIDDLEWARE=[],
SECURE_CONTENT_TYPE_NOSNIFF=False)
def test_no_content_type_nosniff_no_middleware(self):
"""
Don't warn if SECURE_CONTENT_TYPE_NOSNIFF isn't True and
- SecurityMiddleware isn't in MIDDLEWARE_CLASSES.
+ SecurityMiddleware isn't in MIDDLEWARE.
"""
self.assertEqual(self.func(None), [])
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_CONTENT_TYPE_NOSNIFF=True)
def test_with_content_type_nosniff(self):
self.assertEqual(self.func(None), [])
@@ -372,7 +397,7 @@ class CheckXssFilterTest(SimpleTestCase):
return check_xss_filter
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_BROWSER_XSS_FILTER=False)
def test_no_xss_filter(self):
"""
@@ -381,17 +406,17 @@ class CheckXssFilterTest(SimpleTestCase):
self.assertEqual(self.func(None), [base.W007])
@override_settings(
- MIDDLEWARE_CLASSES=[],
+ MIDDLEWARE=[],
SECURE_BROWSER_XSS_FILTER=False)
def test_no_xss_filter_no_middleware(self):
"""
Don't warn if SECURE_BROWSER_XSS_FILTER isn't True and
- SecurityMiddleware isn't in MIDDLEWARE_CLASSES.
+ SecurityMiddleware isn't in MIDDLEWARE.
"""
self.assertEqual(self.func(None), [])
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_BROWSER_XSS_FILTER=True)
def test_with_xss_filter(self):
self.assertEqual(self.func(None), [])
@@ -404,7 +429,7 @@ class CheckSSLRedirectTest(SimpleTestCase):
return check_ssl_redirect
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_SSL_REDIRECT=False)
def test_no_ssl_redirect(self):
"""
@@ -413,7 +438,7 @@ class CheckSSLRedirectTest(SimpleTestCase):
self.assertEqual(self.func(None), [base.W008])
@override_settings(
- MIDDLEWARE_CLASSES=[],
+ MIDDLEWARE=[],
SECURE_SSL_REDIRECT=False)
def test_no_ssl_redirect_no_middleware(self):
"""
@@ -423,7 +448,7 @@ class CheckSSLRedirectTest(SimpleTestCase):
self.assertEqual(self.func(None), [])
@override_settings(
- MIDDLEWARE_CLASSES=["django.middleware.security.SecurityMiddleware"],
+ MIDDLEWARE=["django.middleware.security.SecurityMiddleware"],
SECURE_SSL_REDIRECT=True)
def test_with_ssl_redirect(self):
self.assertEqual(self.func(None), [])
diff --git a/tests/file_uploads/tests.py b/tests/file_uploads/tests.py
index 924b13bec1..2712cf668a 100644
--- a/tests/file_uploads/tests.py
+++ b/tests/file_uploads/tests.py
@@ -27,7 +27,7 @@ MEDIA_ROOT = sys_tempfile.mkdtemp()
UPLOAD_TO = os.path.join(MEDIA_ROOT, 'test_upload')
-@override_settings(MEDIA_ROOT=MEDIA_ROOT, ROOT_URLCONF='file_uploads.urls', MIDDLEWARE_CLASSES=[])
+@override_settings(MEDIA_ROOT=MEDIA_ROOT, ROOT_URLCONF='file_uploads.urls', MIDDLEWARE=[])
class FileUploadTests(TestCase):
@classmethod
diff --git a/tests/flatpages_tests/test_csrf.py b/tests/flatpages_tests/test_csrf.py
index 0ffc567c48..b4ae186d0c 100644
--- a/tests/flatpages_tests/test_csrf.py
+++ b/tests/flatpages_tests/test_csrf.py
@@ -9,7 +9,7 @@ from .settings import FLATPAGES_TEMPLATES
@modify_settings(INSTALLED_APPS={'append': 'django.contrib.flatpages'})
@override_settings(
LOGIN_URL='/accounts/login/',
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
@@ -97,3 +97,18 @@ class FlatpageCSRFTests(TestCase):
"POSTing to an unknown page isn't caught as a 403 CSRF error"
response = self.client.post('/no_such_page/')
self.assertEqual(response.status_code, 404)
+
+
+@override_settings(
+ MIDDLEWARE=None,
+ MIDDLEWARE_CLASSES=[
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
+ ],
+)
+class FlatpageCSRFMiddlewareClassesTests(FlatpageCSRFTests):
+ pass
diff --git a/tests/flatpages_tests/test_forms.py b/tests/flatpages_tests/test_forms.py
index ae9da29f5c..acf6687ea2 100644
--- a/tests/flatpages_tests/test_forms.py
+++ b/tests/flatpages_tests/test_forms.py
@@ -47,18 +47,36 @@ class FlatpageAdminFormTests(TestCase):
self.assertFalse(form.is_valid())
self.assertEqual(form.errors['url'], ["URL is missing a leading slash."])
- @override_settings(APPEND_SLASH=True, MIDDLEWARE_CLASSES=['django.middleware.common.CommonMiddleware'])
+ @override_settings(APPEND_SLASH=True, MIDDLEWARE=['django.middleware.common.CommonMiddleware'])
def test_flatpage_requires_trailing_slash_with_append_slash(self):
form = FlatpageForm(data=dict(url='/no_trailing_slash', **self.form_data))
with translation.override('en'):
self.assertFalse(form.is_valid())
self.assertEqual(form.errors['url'], ["URL is missing a trailing slash."])
- @override_settings(APPEND_SLASH=False, MIDDLEWARE_CLASSES=['django.middleware.common.CommonMiddleware'])
+ @override_settings(APPEND_SLASH=False, MIDDLEWARE=['django.middleware.common.CommonMiddleware'])
def test_flatpage_doesnt_requires_trailing_slash_without_append_slash(self):
form = FlatpageForm(data=dict(url='/no_trailing_slash', **self.form_data))
self.assertTrue(form.is_valid())
+ @override_settings(
+ APPEND_SLASH=True, MIDDLEWARE=None,
+ MIDDLEWARE_CLASSES=['django.middleware.common.CommonMiddleware'],
+ )
+ def test_flatpage_requires_trailing_slash_with_append_slash_middleware_classes(self):
+ form = FlatpageForm(data=dict(url='/no_trailing_slash', **self.form_data))
+ with translation.override('en'):
+ self.assertFalse(form.is_valid())
+ self.assertEqual(form.errors['url'], ["URL is missing a trailing slash."])
+
+ @override_settings(
+ APPEND_SLASH=False, MIDDLEWARE=None,
+ MIDDLEWARE_CLASSES=['django.middleware.common.CommonMiddleware'],
+ )
+ def test_flatpage_doesnt_requires_trailing_slash_without_append_slash_middleware_classes(self):
+ form = FlatpageForm(data=dict(url='/no_trailing_slash', **self.form_data))
+ self.assertTrue(form.is_valid())
+
def test_flatpage_admin_form_url_uniqueness_validation(self):
"The flatpage admin form correctly enforces url uniqueness among flatpages of the same site"
data = dict(url='/myflatpage1/', **self.form_data)
diff --git a/tests/flatpages_tests/test_middleware.py b/tests/flatpages_tests/test_middleware.py
index 37e789d1b1..8d04076af6 100644
--- a/tests/flatpages_tests/test_middleware.py
+++ b/tests/flatpages_tests/test_middleware.py
@@ -40,7 +40,7 @@ class TestDataMixin(object):
@modify_settings(INSTALLED_APPS={'append': 'django.contrib.flatpages'})
@override_settings(
LOGIN_URL='/accounts/login/',
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
@@ -107,11 +107,26 @@ class FlatpageMiddlewareTests(TestDataMixin, TestCase):
self.assertContains(response, "<p>Isn't it special!</p>")
+@override_settings(
+ MIDDLEWARE=None,
+ MIDDLEWARE_CLASSES=[
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
+ ],
+)
+class FlatpageMiddlewareClassesTests(FlatpageMiddlewareTests):
+ pass
+
+
@modify_settings(INSTALLED_APPS={'append': 'django.contrib.flatpages'})
@override_settings(
APPEND_SLASH=True,
LOGIN_URL='/accounts/login/',
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
@@ -172,3 +187,18 @@ class FlatpageMiddlewareAppendSlashTests(TestDataMixin, TestCase):
response = self.client.get('/')
self.assertContains(response, "<p>Root</p>")
+
+
+@override_settings(
+ MIDDLEWARE=None,
+ MIDDLEWARE_CLASSES=[
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
+ ],
+)
+class FlatpageAppendSlashMiddlewareClassesTests(FlatpageMiddlewareAppendSlashTests):
+ pass
diff --git a/tests/flatpages_tests/test_templatetags.py b/tests/flatpages_tests/test_templatetags.py
index d766d13964..688d85a224 100644
--- a/tests/flatpages_tests/test_templatetags.py
+++ b/tests/flatpages_tests/test_templatetags.py
@@ -2,25 +2,9 @@ from django.contrib.auth.models import AnonymousUser, User
from django.contrib.flatpages.models import FlatPage
from django.contrib.sites.models import Site
from django.template import Context, Template, TemplateSyntaxError
-from django.test import TestCase, modify_settings, override_settings
+from django.test import TestCase
-from .settings import FLATPAGES_TEMPLATES
-
-@modify_settings(INSTALLED_APPS={'append': 'django.contrib.flatpages'})
-@override_settings(
- MIDDLEWARE_CLASSES=[
- 'django.middleware.common.CommonMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.csrf.CsrfViewMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.contrib.messages.middleware.MessageMiddleware',
- 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
- ],
- ROOT_URLCONF='flatpages_tests.urls',
- TEMPLATES=FLATPAGES_TEMPLATES,
- SITE_ID=1,
-)
class FlatpageTemplateTagTests(TestCase):
@classmethod
diff --git a/tests/flatpages_tests/test_views.py b/tests/flatpages_tests/test_views.py
index 1a93a543b7..a5104ce620 100644
--- a/tests/flatpages_tests/test_views.py
+++ b/tests/flatpages_tests/test_views.py
@@ -40,7 +40,7 @@ class TestDataMixin(object):
@modify_settings(INSTALLED_APPS={'append': 'django.contrib.flatpages'})
@override_settings(
LOGIN_URL='/accounts/login/',
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
@@ -102,7 +102,7 @@ class FlatpageViewTests(TestDataMixin, TestCase):
@override_settings(
APPEND_SLASH=True,
LOGIN_URL='/accounts/login/',
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
diff --git a/tests/handlers/tests.py b/tests/handlers/tests.py
index d0b161cf44..9f01cb201a 100644
--- a/tests/handlers/tests.py
+++ b/tests/handlers/tests.py
@@ -4,6 +4,7 @@ from __future__ import unicode_literals
import unittest
+from django.core.exceptions import ImproperlyConfigured
from django.core.handlers.wsgi import WSGIHandler, WSGIRequest, get_script_name
from django.core.signals import request_finished, request_started
from django.db import close_old_connections, connection
@@ -166,6 +167,10 @@ class SignalsTests(SimpleTestCase):
self.assertEqual(self.signals, ['started', 'finished'])
+def empty_middleware(get_response):
+ pass
+
+
@override_settings(ROOT_URLCONF='handlers.urls')
class HandlerRequestTests(SimpleTestCase):
@@ -199,6 +204,12 @@ class HandlerRequestTests(SimpleTestCase):
WSGIHandler()(environ, start_response)
self.assertEqual(start_response.status, '200 OK')
+ @override_settings(MIDDLEWARE=['handlers.tests.empty_middleware'])
+ def test_middleware_returns_none(self):
+ msg = 'Middleware factory handlers.tests.empty_middleware returned None.'
+ with self.assertRaisesMessage(ImproperlyConfigured, msg):
+ self.client.get('/')
+
class ScriptNameTests(SimpleTestCase):
def test_get_script_name(self):
diff --git a/tests/i18n/patterns/tests.py b/tests/i18n/patterns/tests.py
index c503a74d34..613a88701f 100644
--- a/tests/i18n/patterns/tests.py
+++ b/tests/i18n/patterns/tests.py
@@ -30,7 +30,7 @@ class PermanentRedirectLocaleMiddleWare(LocaleMiddleware):
('en', 'English'),
('pt-br', 'Brazilian Portuguese'),
],
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
],
@@ -223,7 +223,7 @@ class URLRedirectTests(URLTestCaseBase):
self.assertEqual(response.status_code, 200)
@override_settings(
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'i18n.patterns.tests.PermanentRedirectLocaleMiddleWare',
'django.middleware.common.CommonMiddleware',
],
diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py
index 140e2da187..5084f2dc1d 100644
--- a/tests/i18n/tests.py
+++ b/tests/i18n/tests.py
@@ -1756,7 +1756,7 @@ class MultipleLocaleActivationTests(SimpleTestCase):
('en', 'English'),
('fr', 'French'),
],
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
],
@@ -1772,7 +1772,7 @@ class LocaleMiddlewareTests(TestCase):
self.assertContains(response, "Yes/No")
@override_settings(
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
@@ -1792,7 +1792,7 @@ class LocaleMiddlewareTests(TestCase):
('en', 'English'),
('fr', 'French'),
],
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
],
@@ -1828,7 +1828,7 @@ class UnprefixedDefaultLanguageTests(SimpleTestCase):
('en-us', 'English'),
('pt-br', 'Portuguese (Brazil)'),
],
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
],
diff --git a/tests/logging_tests/tests.py b/tests/logging_tests/tests.py
index 058abfb4a3..1802a0ce47 100644
--- a/tests/logging_tests/tests.py
+++ b/tests/logging_tests/tests.py
@@ -125,7 +125,7 @@ class HandlerLoggingTests(SetupDefaultLoggingMixin, LoggingCaptureMixin, SimpleT
DEBUG=True,
USE_I18N=True,
LANGUAGES=[('en', 'English')],
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
],
diff --git a/tests/messages_tests/base.py b/tests/messages_tests/base.py
index 3284522edf..7b6cd43a1d 100644
--- a/tests/messages_tests/base.py
+++ b/tests/messages_tests/base.py
@@ -217,7 +217,7 @@ class BaseTests(object):
@modify_settings(
INSTALLED_APPS={'remove': 'django.contrib.messages'},
- MIDDLEWARE_CLASSES={'remove': 'django.contrib.messages.middleware.MessageMiddleware'},
+ MIDDLEWARE={'remove': 'django.contrib.messages.middleware.MessageMiddleware'},
)
@override_settings(
MESSAGE_LEVEL=constants.DEBUG,
@@ -243,7 +243,7 @@ class BaseTests(object):
@modify_settings(
INSTALLED_APPS={'remove': 'django.contrib.messages'},
- MIDDLEWARE_CLASSES={'remove': 'django.contrib.messages.middleware.MessageMiddleware'},
+ MIDDLEWARE={'remove': 'django.contrib.messages.middleware.MessageMiddleware'},
)
@override_settings(
TEMPLATES=[{
diff --git a/tests/middleware_exceptions/middleware.py b/tests/middleware_exceptions/middleware.py
index 944dd8910d..6871d9556e 100644
--- a/tests/middleware_exceptions/middleware.py
+++ b/tests/middleware_exceptions/middleware.py
@@ -1,8 +1,10 @@
from __future__ import unicode_literals
from django.http import HttpResponse
+from django.utils.deprecation import MiddlewareMixin
-class ProcessExceptionMiddleware(object):
+class ProcessExceptionMiddleware(MiddlewareMixin):
+
def process_exception(self, request, exception):
return HttpResponse('Exception caught')
diff --git a/tests/middleware_exceptions/tests.py b/tests/middleware_exceptions/tests.py
index ef9d19fe21..13b33632f8 100644
--- a/tests/middleware_exceptions/tests.py
+++ b/tests/middleware_exceptions/tests.py
@@ -8,6 +8,7 @@ from django.template import engines
from django.template.response import TemplateResponse
from django.test import RequestFactory, SimpleTestCase, override_settings
from django.test.utils import patch_logger
+from django.utils.deprecation import MiddlewareMixin
class TestException(Exception):
@@ -15,13 +16,14 @@ class TestException(Exception):
# A middleware base class that tracks which methods have been called
-class TestMiddleware(object):
- def __init__(self):
+class TestMiddleware(MiddlewareMixin):
+ def __init__(self, get_response=None):
self.process_request_called = False
self.process_view_called = False
self.process_response_called = False
self.process_template_response_called = False
self.process_exception_called = False
+ self.get_response = get_response
def process_request(self, request):
self.process_request_called = True
@@ -115,7 +117,11 @@ class NoResponseMiddleware(TestMiddleware):
super(NoResponseMiddleware, self).process_response(request, response)
-@override_settings(ROOT_URLCONF='middleware_exceptions.urls')
+@override_settings(
+ ROOT_URLCONF='middleware_exceptions.urls',
+ MIDDLEWARE_CLASSES=['django.middleware.common.CommonMiddleware'],
+ MIDDLEWARE=None,
+)
class BaseMiddlewareExceptionTest(SimpleTestCase):
def setUp(self):
@@ -492,12 +498,10 @@ class MiddlewareTests(BaseMiddlewareExceptionTest):
# Check that the right middleware methods have been invoked
self.assert_middleware_usage(middleware, True, True, True, True, False)
- @override_settings(
- MIDDLEWARE_CLASSES=['middleware_exceptions.middleware.ProcessExceptionMiddleware'],
- )
+ @override_settings(MIDDLEWARE=['middleware_exceptions.middleware.ProcessExceptionMiddleware'])
def test_exception_in_render_passed_to_process_exception(self):
# Repopulate the list of middlewares since it's already been populated
- # by setUp() before the MIDDLEWARE_CLASSES setting got overridden
+ # by setUp() before the MIDDLEWARE setting got overridden.
self.client.handler.load_middleware()
response = self.client.get('/middleware_exceptions/exception_in_render/')
self.assertEqual(response.content, b'Exception caught')
@@ -868,7 +872,7 @@ class RootUrlconfTests(SimpleTestCase):
class MyMiddleware(object):
- def __init__(self):
+ def __init__(self, get_response=None):
raise MiddlewareNotUsed
def process_request(self, request):
@@ -877,7 +881,7 @@ class MyMiddleware(object):
class MyMiddlewareWithExceptionMessage(object):
- def __init__(self):
+ def __init__(self, get_response=None):
raise MiddlewareNotUsed('spam eggs')
def process_request(self, request):
@@ -887,6 +891,7 @@ class MyMiddlewareWithExceptionMessage(object):
@override_settings(
DEBUG=True,
ROOT_URLCONF='middleware_exceptions.urls',
+ MIDDLEWARE=['django.middleware.common.CommonMiddleware'],
)
class MiddlewareNotUsedTests(SimpleTestCase):
@@ -897,9 +902,7 @@ class MiddlewareNotUsedTests(SimpleTestCase):
with self.assertRaises(MiddlewareNotUsed):
MyMiddleware().process_request(request)
- @override_settings(MIDDLEWARE_CLASSES=[
- 'middleware_exceptions.tests.MyMiddleware',
- ])
+ @override_settings(MIDDLEWARE=['middleware_exceptions.tests.MyMiddleware'])
def test_log(self):
with patch_logger('django.request', 'debug') as calls:
self.client.get('/middleware_exceptions/view/')
@@ -909,9 +912,7 @@ class MiddlewareNotUsedTests(SimpleTestCase):
"MiddlewareNotUsed: 'middleware_exceptions.tests.MyMiddleware'"
)
- @override_settings(MIDDLEWARE_CLASSES=[
- 'middleware_exceptions.tests.MyMiddlewareWithExceptionMessage',
- ])
+ @override_settings(MIDDLEWARE=['middleware_exceptions.tests.MyMiddlewareWithExceptionMessage'])
def test_log_custom_message(self):
with patch_logger('django.request', 'debug') as calls:
self.client.get('/middleware_exceptions/view/')
@@ -926,3 +927,11 @@ class MiddlewareNotUsedTests(SimpleTestCase):
with patch_logger('django.request', 'debug') as calls:
self.client.get('/middleware_exceptions/view/')
self.assertEqual(len(calls), 0)
+
+
+@override_settings(
+ MIDDLEWARE_CLASSES=['django.middleware.common.CommonMiddleware'],
+ MIDDLEWARE=None,
+)
+class MiddlewareNotUsedMiddlewareClassesTests(MiddlewareNotUsedTests):
+ pass
diff --git a/tests/project_template/test_settings.py b/tests/project_template/test_settings.py
index 702ecec8c5..d153c4d95f 100644
--- a/tests/project_template/test_settings.py
+++ b/tests/project_template/test_settings.py
@@ -26,16 +26,16 @@ class TestStartProjectSettings(TestCase):
shutil.copyfile(template_settings_py, test_settings_py)
self.addCleanup(os.remove, test_settings_py)
- def test_middleware_classes_headers(self):
+ def test_middleware_headers(self):
"""
- Ensure headers sent by the default MIDDLEWARE_CLASSES do not
- inadvertently change. For example, we never want "Vary: Cookie" to
- appear in the list since it prevents the caching of responses.
+ Ensure headers sent by the default MIDDLEWARE don't inadvertently
+ change. For example, we never want "Vary: Cookie" to appear in the list
+ since it prevents the caching of responses.
"""
- from django.conf.project_template.project_name.settings import MIDDLEWARE_CLASSES
+ from django.conf.project_template.project_name.settings import MIDDLEWARE
with self.settings(
- MIDDLEWARE_CLASSES=MIDDLEWARE_CLASSES,
+ MIDDLEWARE=MIDDLEWARE,
ROOT_URLCONF='project_template.urls',
):
response = self.client.get('/empty/')
diff --git a/tests/redirects_tests/tests.py b/tests/redirects_tests/tests.py
index 2d9793b0a5..b4210ad49b 100644
--- a/tests/redirects_tests/tests.py
+++ b/tests/redirects_tests/tests.py
@@ -8,7 +8,7 @@ from django.test import TestCase, modify_settings, override_settings
from django.utils import six
-@modify_settings(MIDDLEWARE_CLASSES={'append': 'django.contrib.redirects.middleware.RedirectFallbackMiddleware'})
+@modify_settings(MIDDLEWARE={'append': 'django.contrib.redirects.middleware.RedirectFallbackMiddleware'})
@override_settings(APPEND_SLASH=False, SITE_ID=1)
class RedirectTests(TestCase):
@@ -42,6 +42,18 @@ class RedirectTests(TestCase):
response = self.client.get('/initial')
self.assertEqual(response.status_code, 410)
+ @override_settings(MIDDLEWARE=None)
+ @modify_settings(MIDDLEWARE_CLASSES={'append': 'django.contrib.redirects.middleware.RedirectFallbackMiddleware'})
+ def test_redirect_middleware_classes(self):
+ self.test_redirect()
+
+ @override_settings(MIDDLEWARE=None)
+ @modify_settings(MIDDLEWARE_CLASSES={'append': 'django.contrib.redirects.middleware.RedirectFallbackMiddleware'})
+ def test_more_redirects_middleware_classes(self):
+ self.test_redirect_with_append_slash()
+ self.test_redirect_with_append_slash_and_query_string()
+ self.test_response_gone()
+
@modify_settings(INSTALLED_APPS={'remove': 'django.contrib.sites'})
def test_sites_not_installed(self):
with self.assertRaises(ImproperlyConfigured):
@@ -54,7 +66,7 @@ class OverriddenRedirectFallbackMiddleware(RedirectFallbackMiddleware):
response_redirect_class = http.HttpResponseRedirect
-@modify_settings(MIDDLEWARE_CLASSES={'append': 'redirects_tests.tests.OverriddenRedirectFallbackMiddleware'})
+@modify_settings(MIDDLEWARE={'append': 'redirects_tests.tests.OverriddenRedirectFallbackMiddleware'})
@override_settings(SITE_ID=1)
class OverriddenRedirectMiddlewareTests(TestCase):
diff --git a/tests/runtests.py b/tests/runtests.py
index aedd4aa932..122cb73282 100755
--- a/tests/runtests.py
+++ b/tests/runtests.py
@@ -62,7 +62,7 @@ ALWAYS_INSTALLED_APPS = [
'django.contrib.staticfiles',
]
-ALWAYS_MIDDLEWARE_CLASSES = [
+ALWAYS_MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
@@ -124,7 +124,7 @@ def setup(verbosity, test_labels, parallel):
'LANGUAGE_CODE': settings.LANGUAGE_CODE,
'STATIC_URL': settings.STATIC_URL,
'STATIC_ROOT': settings.STATIC_ROOT,
- 'MIDDLEWARE_CLASSES': settings.MIDDLEWARE_CLASSES,
+ 'MIDDLEWARE': settings.MIDDLEWARE,
}
# Redirect some settings for the duration of these tests.
@@ -147,7 +147,7 @@ def setup(verbosity, test_labels, parallel):
}]
settings.LANGUAGE_CODE = 'en'
settings.SITE_ID = 1
- settings.MIDDLEWARE_CLASSES = ALWAYS_MIDDLEWARE_CLASSES
+ settings.MIDDLEWARE = ALWAYS_MIDDLEWARE
settings.MIGRATION_MODULES = {
# This lets us skip creating migrations for the test models as many of
# them depend on one of the following contrib applications.
diff --git a/tests/template_tests/test_response.py b/tests/template_tests/test_response.py
index 85b5f4bf0f..c2ece4b2a8 100644
--- a/tests/template_tests/test_response.py
+++ b/tests/template_tests/test_response.py
@@ -4,13 +4,15 @@ import pickle
import time
from datetime import datetime
-from django.conf import settings
from django.template import engines
from django.template.response import (
ContentNotRenderedError, SimpleTemplateResponse, TemplateResponse,
)
-from django.test import RequestFactory, SimpleTestCase, override_settings
+from django.test import (
+ RequestFactory, SimpleTestCase, modify_settings, override_settings,
+)
from django.test.utils import require_jinja2
+from django.utils.deprecation import MiddlewareMixin
from .utils import TEMPLATE_DIR
@@ -21,7 +23,7 @@ test_processor_name = 'template_tests.test_response.test_processor'
# A test middleware that installs a temporary URLConf
-class CustomURLConfMiddleware(object):
+class CustomURLConfMiddleware(MiddlewareMixin):
def process_request(self, request):
request.urlconf = 'template_tests.alternate_urls'
@@ -319,12 +321,8 @@ class TemplateResponseTest(SimpleTestCase):
pickle.dumps(unpickled_response)
-@override_settings(
- MIDDLEWARE_CLASSES=settings.MIDDLEWARE_CLASSES + [
- 'template_tests.test_response.CustomURLConfMiddleware'
- ],
- ROOT_URLCONF='template_tests.urls',
-)
+@modify_settings(MIDDLEWARE={'append': ['template_tests.test_response.CustomURLConfMiddleware']})
+@override_settings(ROOT_URLCONF='template_tests.urls')
class CustomURLConfTest(SimpleTestCase):
def test_custom_urlconf(self):
@@ -332,16 +330,47 @@ class CustomURLConfTest(SimpleTestCase):
self.assertContains(response, 'This is where you can find the snark: /snark/')
+@modify_settings(
+ MIDDLEWARE={
+ 'append': [
+ 'django.middleware.cache.FetchFromCacheMiddleware',
+ 'django.middleware.cache.UpdateCacheMiddleware',
+ ],
+ },
+)
+@override_settings(CACHE_MIDDLEWARE_SECONDS=2.0, ROOT_URLCONF='template_tests.alternate_urls')
+class CacheMiddlewareTest(SimpleTestCase):
+
+ def test_middleware_caching(self):
+ response = self.client.get('/template_response_view/')
+ self.assertEqual(response.status_code, 200)
+
+ time.sleep(1.0)
+
+ response2 = self.client.get('/template_response_view/')
+ self.assertEqual(response2.status_code, 200)
+
+ self.assertEqual(response.content, response2.content)
+
+ time.sleep(2.0)
+
+ # Let the cache expire and test again
+ response2 = self.client.get('/template_response_view/')
+ self.assertEqual(response2.status_code, 200)
+
+ self.assertNotEqual(response.content, response2.content)
+
+
@override_settings(
- CACHE_MIDDLEWARE_SECONDS=2.0,
- MIDDLEWARE_CLASSES=settings.MIDDLEWARE_CLASSES + [
+ MIDDLEWARE=None,
+ MIDDLEWARE_CLASSES=[
'django.middleware.cache.FetchFromCacheMiddleware',
'django.middleware.cache.UpdateCacheMiddleware',
],
- ROOT_URLCONF='template_tests.alternate_urls',
+ CACHE_MIDDLEWARE_SECONDS=2.0,
+ ROOT_URLCONF='template_tests.alternate_urls'
)
-class CacheMiddlewareTest(SimpleTestCase):
-
+class CacheMiddlewareClassesTest(SimpleTestCase):
def test_middleware_caching(self):
response = self.client.get('/template_response_view/')
self.assertEqual(response.status_code, 200)
diff --git a/tests/test_client/tests.py b/tests/test_client/tests.py
index dff7e39080..5236846ae6 100644
--- a/tests/test_client/tests.py
+++ b/tests/test_client/tests.py
@@ -694,7 +694,7 @@ class ClientTest(TestCase):
@override_settings(
- MIDDLEWARE_CLASSES=['django.middleware.csrf.CsrfViewMiddleware'],
+ MIDDLEWARE=['django.middleware.csrf.CsrfViewMiddleware'],
ROOT_URLCONF='test_client.urls',
)
class CSRFEnabledClientTests(SimpleTestCase):
diff --git a/tests/urlpatterns_reverse/middleware.py b/tests/urlpatterns_reverse/middleware.py
index 13c3d104b6..8c40125f10 100644
--- a/tests/urlpatterns_reverse/middleware.py
+++ b/tests/urlpatterns_reverse/middleware.py
@@ -1,37 +1,38 @@
from django.http import HttpResponse, StreamingHttpResponse
from django.urls import reverse
+from django.utils.deprecation import MiddlewareMixin
from . import urlconf_inner
-class ChangeURLconfMiddleware(object):
+class ChangeURLconfMiddleware(MiddlewareMixin):
def process_request(self, request):
request.urlconf = urlconf_inner.__name__
-class NullChangeURLconfMiddleware(object):
+class NullChangeURLconfMiddleware(MiddlewareMixin):
def process_request(self, request):
request.urlconf = None
-class ReverseInnerInResponseMiddleware(object):
+class ReverseInnerInResponseMiddleware(MiddlewareMixin):
def process_response(self, *args, **kwargs):
return HttpResponse(reverse('inner'))
-class ReverseOuterInResponseMiddleware(object):
+class ReverseOuterInResponseMiddleware(MiddlewareMixin):
def process_response(self, *args, **kwargs):
return HttpResponse(reverse('outer'))
-class ReverseInnerInStreaming(object):
+class ReverseInnerInStreaming(MiddlewareMixin):
def process_view(self, *args, **kwargs):
def stream():
yield reverse('inner')
return StreamingHttpResponse(stream())
-class ReverseOuterInStreaming(object):
+class ReverseOuterInStreaming(MiddlewareMixin):
def process_view(self, *args, **kwargs):
def stream():
yield reverse('outer')
diff --git a/tests/urlpatterns_reverse/tests.py b/tests/urlpatterns_reverse/tests.py
index 4c60ecd7c6..074a573cd5 100644
--- a/tests/urlpatterns_reverse/tests.py
+++ b/tests/urlpatterns_reverse/tests.py
@@ -785,7 +785,7 @@ class RequestURLconfTests(SimpleTestCase):
self.assertEqual(response.status_code, 404)
@override_settings(
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'%s.ChangeURLconfMiddleware' % middleware.__name__,
]
)
@@ -799,7 +799,7 @@ class RequestURLconfTests(SimpleTestCase):
self.assertEqual(response.content, b'outer:,inner:/second_test/')
@override_settings(
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'%s.NullChangeURLconfMiddleware' % middleware.__name__,
]
)
@@ -817,7 +817,7 @@ class RequestURLconfTests(SimpleTestCase):
self.assertEqual(response.status_code, 404)
@override_settings(
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'%s.ChangeURLconfMiddleware' % middleware.__name__,
'%s.ReverseInnerInResponseMiddleware' % middleware.__name__,
]
@@ -832,7 +832,7 @@ class RequestURLconfTests(SimpleTestCase):
self.assertEqual(response.content, b'/second_test/')
@override_settings(
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'%s.ChangeURLconfMiddleware' % middleware.__name__,
'%s.ReverseOuterInResponseMiddleware' % middleware.__name__,
]
@@ -847,7 +847,7 @@ class RequestURLconfTests(SimpleTestCase):
self.client.get('/second_test/')
@override_settings(
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'%s.ChangeURLconfMiddleware' % middleware.__name__,
'%s.ReverseInnerInStreaming' % middleware.__name__,
]
@@ -862,7 +862,7 @@ class RequestURLconfTests(SimpleTestCase):
self.assertEqual(b''.join(response), b'/second_test/')
@override_settings(
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'%s.ChangeURLconfMiddleware' % middleware.__name__,
'%s.ReverseOuterInStreaming' % middleware.__name__,
]
diff --git a/tests/view_tests/tests/test_csrf.py b/tests/view_tests/tests/test_csrf.py
index 4b21e59034..22bf96529f 100644
--- a/tests/view_tests/tests/test_csrf.py
+++ b/tests/view_tests/tests/test_csrf.py
@@ -15,7 +15,7 @@ class CsrfViewTests(SimpleTestCase):
@override_settings(
USE_I18N=True,
- MIDDLEWARE_CLASSES=[
+ MIDDLEWARE=[
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
@@ -39,6 +39,32 @@ class CsrfViewTests(SimpleTestCase):
status_code=403)
@override_settings(
+ USE_I18N=True,
+ MIDDLEWARE=None,
+ MIDDLEWARE_CLASSES=[
+ 'django.middleware.locale.LocaleMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ ],
+ )
+ def test_translation_middleware_classes(self):
+ """
+ Test that an invalid request is rejected with a localized error message.
+ """
+ response = self.client.post('/')
+ self.assertContains(response, "Forbidden", status_code=403)
+ self.assertContains(response,
+ "CSRF verification failed. Request aborted.",
+ status_code=403)
+
+ with self.settings(LANGUAGE_CODE='nl'), override('en-us'):
+ response = self.client.post('/')
+ self.assertContains(response, "Verboden", status_code=403)
+ self.assertContains(response,
+ "CSRF-verificatie mislukt. Verzoek afgebroken.",
+ status_code=403)
+
+ @override_settings(
SECURE_PROXY_SSL_HEADER=('HTTP_X_FORWARDED_PROTO', 'https')
)
def test_no_referer(self):
diff --git a/tests/view_tests/tests/test_i18n.py b/tests/view_tests/tests/test_i18n.py
index 84a381909d..a50b7d6460 100644
--- a/tests/view_tests/tests/test_i18n.py
+++ b/tests/view_tests/tests/test_i18n.py
@@ -123,6 +123,26 @@ class I18NTests(TestCase):
# we force saving language to a cookie rather than a session
# by excluding session middleware and those which do require it
test_settings = dict(
+ MIDDLEWARE=['django.middleware.common.CommonMiddleware'],
+ LANGUAGE_COOKIE_NAME='mylanguage',
+ LANGUAGE_COOKIE_AGE=3600 * 7 * 2,
+ LANGUAGE_COOKIE_DOMAIN='.example.com',
+ LANGUAGE_COOKIE_PATH='/test/',
+ )
+ with self.settings(**test_settings):
+ post_data = dict(language='pl', next='/views/')
+ response = self.client.post('/i18n/setlang/', data=post_data)
+ language_cookie = response.cookies.get('mylanguage')
+ self.assertEqual(language_cookie.value, 'pl')
+ self.assertEqual(language_cookie['domain'], '.example.com')
+ self.assertEqual(language_cookie['path'], '/test/')
+ self.assertEqual(language_cookie['max-age'], 3600 * 7 * 2)
+
+ def test_setlang_cookie_middleware_classes(self):
+ # we force saving language to a cookie rather than a session
+ # by excluding session middleware and those which do require it
+ test_settings = dict(
+ MIDDLEWARE=None,
MIDDLEWARE_CLASSES=['django.middleware.common.CommonMiddleware'],
LANGUAGE_COOKIE_NAME='mylanguage',
LANGUAGE_COOKIE_AGE=3600 * 7 * 2,
@@ -150,7 +170,7 @@ class I18NTests(TestCase):
self.assertRedirects(response, encoded_url, fetch_redirect_response=False)
self.assertEqual(self.client.session[LANGUAGE_SESSION_KEY], lang_code)
- @modify_settings(MIDDLEWARE_CLASSES={
+ @modify_settings(MIDDLEWARE={
'append': 'django.middleware.locale.LocaleMiddleware',
})
def test_lang_from_translated_i18n_pattern(self):
@@ -167,6 +187,27 @@ class I18NTests(TestCase):
)
self.assertRedirects(response, '/en/translated/')
+ @override_settings(
+ MIDDLEWARE=None,
+ MIDDLEWARE_CLASSES=[
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.locale.LocaleMiddleware',
+ ],
+ )
+ def test_lang_from_translated_i18n_pattern_middleware_classes(self):
+ response = self.client.post(
+ '/i18n/setlang/', data={'language': 'nl'},
+ follow=True, HTTP_REFERER='/en/translated/'
+ )
+ self.assertEqual(self.client.session[LANGUAGE_SESSION_KEY], 'nl')
+ self.assertRedirects(response, '/nl/vertaald/')
+ # And reverse
+ response = self.client.post(
+ '/i18n/setlang/', data={'language': 'en'},
+ follow=True, HTTP_REFERER='/nl/vertaald/'
+ )
+ self.assertRedirects(response, '/en/translated/')
+
@override_settings(ROOT_URLCONF='view_tests.urls')
class JsI18NTests(SimpleTestCase):