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.
This commit is contained in:
Florian Apolloner 2015-11-07 16:12:37 +01:00 committed by Tim Graham
parent 05c888ffb8
commit 9baf692a58
81 changed files with 900 additions and 1414 deletions

View File

@ -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 #
############

View File

@ -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',

View File

@ -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 = [

View File

@ -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()

View File

@ -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:

View File

@ -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."),

View File

@ -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.

View File

@ -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.
"""

View File

@ -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):

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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)]

View File

@ -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():

View File

@ -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

View File

@ -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)
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)
handler = mw_instance
handler = ExceptionMiddleware(handler, self)

View File

@ -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,

View File

@ -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.

View File

@ -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):
"""

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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("/")

View File

@ -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)

View File

@ -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

View File

@ -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 %}

View File

@ -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',

View File

@ -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

View File

@ -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

View File

@ -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'``.

View File

@ -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',
...

View File

@ -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.

View File

@ -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

View File

@ -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
==============================

View File

@ -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>`.

View File

@ -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
===================================

View File

@ -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

View File

@ -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
---------------

View File

@ -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',

View File

@ -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

View File

@ -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

View File

@ -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
--------------------------------------

View File

@ -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
-------------------------------

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@ -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:
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.
* :meth:`process_request`
* :meth:`process_view`
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.
During the response phase, after calling the view, middleware are applied in
reverse order, from the bottom up. Three hooks are available:
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``.
* :meth:`process_exception` (only if the view raised an exception)
* :meth:`process_template_response` (only for template responses)
* :meth:`process_response`
.. image:: _images/middleware.*
:alt: middleware application order
:width: 481
:height: 409
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
===========================
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.
.. class:: django.utils.deprecation.MiddlewareMixin
:module:
* Unlike the ``process_*`` methods which get called once per request,
``__init__`` gets called only *once*, when the Web server starts.
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.
.. versionchanged:: 1.10
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.
In older versions, ``__init__`` was not called until the Web server
responded to its first request.
In a few cases, a middleware class may need more invasive changes to adjust to
the new semantics.
Marking middleware as unused
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
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``.
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.
Guidelines
----------
* Middleware classes don't have to subclass anything.
* 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.
* Feel free to look at :doc:`Django's available middleware
</ref/middleware>` for examples.
* 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`.

View File

@ -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.

View File

@ -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`

View File

@ -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:

View File

@ -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',

View File

@ -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',
})

View File

@ -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',
]

View File

@ -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(

View File

@ -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

View File

@ -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
@ -21,22 +22,38 @@ class CheckSessionCookieSecureTest(SimpleTestCase):
"""
self.assertEqual(self.func(None), [sessions.W010])
@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
@ -44,10 +61,18 @@ class CheckSessionCookieSecureTest(SimpleTestCase):
"""
self.assertEqual(self.func(None), [sessions.W012])
@override_settings(
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_CLASSES=["django.contrib.sessions.middleware.SessionMiddleware"])
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), [])

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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 .settings import FLATPAGES_TEMPLATES
from django.test import TestCase
@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

View File

@ -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',

View File

@ -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):

View File

@ -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',
],

View File

@ -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',
],

View File

@ -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',
],

View File

@ -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=[{

View File

@ -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')

View File

@ -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

View File

@ -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/')

View File

@ -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):

View File

@ -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.

View File

@ -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,14 +330,15 @@ class CustomURLConfTest(SimpleTestCase):
self.assertContains(response, 'This is where you can find the snark: /snark/')
@override_settings(
CACHE_MIDDLEWARE_SECONDS=2.0,
MIDDLEWARE_CLASSES=settings.MIDDLEWARE_CLASSES + [
'django.middleware.cache.FetchFromCacheMiddleware',
'django.middleware.cache.UpdateCacheMiddleware',
],
ROOT_URLCONF='template_tests.alternate_urls',
@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):
@ -360,3 +359,33 @@ class CacheMiddlewareTest(SimpleTestCase):
self.assertEqual(response2.status_code, 200)
self.assertNotEqual(response.content, response2.content)
@override_settings(
MIDDLEWARE=None,
MIDDLEWARE_CLASSES=[
'django.middleware.cache.FetchFromCacheMiddleware',
'django.middleware.cache.UpdateCacheMiddleware',
],
CACHE_MIDDLEWARE_SECONDS=2.0,
ROOT_URLCONF='template_tests.alternate_urls'
)
class CacheMiddlewareClassesTest(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)

View File

@ -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):

View File

@ -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')

View File

@ -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__,
]

View File

@ -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',
@ -38,6 +38,32 @@ class CsrfViewTests(SimpleTestCase):
"CSRF-verificatie mislukt. Verzoek afgebroken.",
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')
)

View File

@ -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):