Code

Ticket #730: middleware_dict_single_instances_basic_sanity_checks.diff

File middleware_dict_single_instances_basic_sanity_checks.diff, 8.8 KB (added by mrts, 6 years ago)

Improved dict middleware setting. Single instances, basic hasattr('process_foo', mw) checks.

Line 
1Index: django/conf/project_template/settings.py
2===================================================================
3--- django/conf/project_template/settings.py    (revision 8255)
4+++ django/conf/project_template/settings.py    (working copy)
5@@ -57,12 +57,22 @@
6 #     'django.template.loaders.eggs.load_template_source',
7 )
8 
9-MIDDLEWARE_CLASSES = (
10-    'django.middleware.common.CommonMiddleware',
11-    'django.contrib.sessions.middleware.SessionMiddleware',
12-    'django.contrib.auth.middleware.AuthenticationMiddleware',
13-    'django.middleware.doc.XViewMiddleware',
14-)
15+MIDDLEWARE_CLASSES = {
16+    'request': (
17+        'django.middleware.common.CommonMiddleware',
18+        'django.contrib.sessions.middleware.SessionMiddleware',
19+        'django.contrib.auth.middleware.AuthenticationMiddleware',
20+    ),
21+    'response': (
22+        'django.contrib.sessions.middleware.SessionMiddleware',
23+#        'django.middleware.http.ConditionalGetMiddleware',
24+#        'django.middleware.gzip.GZipMiddleware',
25+        'django.middleware.common.CommonMiddleware',
26+    ),
27+    'view': (
28+        'django.middleware.doc.XViewMiddleware',
29+    ),
30+}
31 
32 ROOT_URLCONF = '{{ project_name }}.urls'
33 
34Index: django/conf/global_settings.py
35===================================================================
36--- django/conf/global_settings.py      (revision 8255)
37+++ django/conf/global_settings.py      (working copy)
38@@ -291,17 +291,24 @@
39 # MIDDLEWARE #
40 ##############
41 
42-# List of middleware classes to use.  Order is important; in the request phase,
43-# this middleware classes will be applied in the order given, and in the
44-# response phase the middleware will be applied in reverse order.
45-MIDDLEWARE_CLASSES = (
46-    'django.contrib.sessions.middleware.SessionMiddleware',
47-    'django.contrib.auth.middleware.AuthenticationMiddleware',
48-#     'django.middleware.http.ConditionalGetMiddleware',
49-#     'django.middleware.gzip.GZipMiddleware',
50-    'django.middleware.common.CommonMiddleware',
51-    'django.middleware.doc.XViewMiddleware',
52-)
53+# List of middleware classes to use.  Order is important; all middleware types
54+# will be applied in the order given.
55+MIDDLEWARE_CLASSES = {
56+    'request': (
57+        'django.middleware.common.CommonMiddleware',
58+        'django.contrib.sessions.middleware.SessionMiddleware',
59+        'django.contrib.auth.middleware.AuthenticationMiddleware',
60+    ),
61+    'response': (
62+        'django.contrib.sessions.middleware.SessionMiddleware',
63+#        'django.middleware.http.ConditionalGetMiddleware',
64+#        'django.middleware.gzip.GZipMiddleware',
65+        'django.middleware.common.CommonMiddleware',
66+    ),
67+    'view': (
68+        'django.middleware.doc.XViewMiddleware',
69+    ),
70+}
71 
72 ############
73 # SESSIONS #
74Index: django/core/handlers/base.py
75===================================================================
76--- django/core/handlers/base.py        (revision 8255)
77+++ django/core/handlers/base.py        (working copy)
78@@ -1,6 +1,7 @@
79 import sys
80 
81 from django import http
82+from django.core import exceptions
83 from django.core import signals
84 from django.utils.encoding import force_unicode
85 
86@@ -16,38 +17,14 @@
87     def __init__(self):
88         self._request_middleware = self._view_middleware = self._response_middleware = self._exception_middleware = None
89 
90-    def load_middleware(self):
91-        """
92-        Populate middleware lists from settings.MIDDLEWARE_CLASSES.
93-
94-        Must be called after the environment is fixed (see __call__).
95-        """
96-        from django.conf import settings
97-        from django.core import exceptions
98+    def _load_middleware_from_list(self, mw_paths):
99         self._request_middleware = []
100         self._view_middleware = []
101         self._response_middleware = []
102         self._exception_middleware = []
103-        for middleware_path in settings.MIDDLEWARE_CLASSES:
104-            try:
105-                dot = middleware_path.rindex('.')
106-            except ValueError:
107-                raise exceptions.ImproperlyConfigured, '%s isn\'t a middleware module' % middleware_path
108-            mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:]
109-            try:
110-                mod = __import__(mw_module, {}, {}, [''])
111-            except ImportError, e:
112-                raise exceptions.ImproperlyConfigured, 'Error importing middleware %s: "%s"' % (mw_module, e)
113-            try:
114-                mw_class = getattr(mod, mw_classname)
115-            except AttributeError:
116-                raise exceptions.ImproperlyConfigured, 'Middleware module "%s" does not define a "%s" class' % (mw_module, mw_classname)
117-
118-            try:
119-                mw_instance = mw_class()
120-            except exceptions.MiddlewareNotUsed:
121-                continue
122-
123+        mw_instances = [ _middleware_instance_from_path(mw_path) for mw_path
124+                in mw_paths ]
125+        for mw_instance in mw_instances:
126             if hasattr(mw_instance, 'process_request'):
127                 self._request_middleware.append(mw_instance.process_request)
128             if hasattr(mw_instance, 'process_view'):
129@@ -57,9 +34,42 @@
130             if hasattr(mw_instance, 'process_exception'):
131                 self._exception_middleware.insert(0, mw_instance.process_exception)
132 
133+    def _load_middleware_from_dict(self, mw_dict):
134+        # fill the instances dict so that we have only one instance of each
135+        # middleware
136+        mw_instances = {}
137+        for mw_path_tuple in mw_dict.values():
138+            for mw_path in mw_path_tuple:
139+                if mw_path not in mw_instances:
140+                    mw_instances[mw_path] = _middleware_instance_from_path(mw_path)
141+
142+        self._request_middleware = _middleware_type_from_dicts('request',
143+                mw_instances, mw_dict)
144+        self._view_middleware = _middleware_type_from_dicts('view',
145+                mw_instances, mw_dict)
146+        self._response_middleware = _middleware_type_from_dicts('response',
147+                mw_instances, mw_dict)
148+        self._exception_middleware = _middleware_type_from_dicts('exception',
149+                mw_instances, mw_dict)
150+
151+    def load_middleware(self):
152+        """
153+        Populate middleware lists from settings.MIDDLEWARE_CLASSES.
154+
155+        Must be called after the environment is fixed (see __call__).
156+        """
157+        from django.conf import settings
158+        if isinstance(settings.MIDDLEWARE_CLASSES, (tuple, list)):
159+            self._load_middleware_from_list(settings.MIDDLEWARE_CLASSES)
160+        elif isinstance(settings.MIDDLEWARE_CLASSES, (dict)):
161+            self._load_middleware_from_dict(settings.MIDDLEWARE_CLASSES)
162+        else:
163+            raise ImproperlyConfigured("MIDDLEWARE_CLASSES setting has to be"
164+                    "either a tuple, list or a dict.")
165+
166     def get_response(self, request):
167         "Returns an HttpResponse object for the given HttpRequest"
168-        from django.core import exceptions, urlresolvers
169+        from django.core import urlresolvers
170         from django.conf import settings
171 
172         # Apply request middleware
173@@ -195,3 +205,35 @@
174         return force_unicode(script_url[:-len(environ.get('PATH_INFO', ''))])
175     return force_unicode(environ.get('SCRIPT_NAME', u''))
176 
177+def _middleware_instance_from_path(middleware_path):
178+    try:
179+        dot = middleware_path.rindex('.')
180+    except ValueError:
181+        raise exceptions.ImproperlyConfigured, '%s isn\'t a middleware module' % middleware_path
182+    mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:]
183+    try:
184+        mod = __import__(mw_module, {}, {}, [''])
185+    except ImportError, e:
186+        raise exceptions.ImproperlyConfigured, 'Error importing middleware %s: "%s"' % (mw_module, e)
187+    try:
188+        mw_class = getattr(mod, mw_classname)
189+    except AttributeError:
190+        raise exceptions.ImproperlyConfigured, 'Middleware module "%s" does not define a "%s" class' % (mw_module, mw_classname)
191+    # I'm ignoring the MiddlewareNotUsed exception as it's not used in Django
192+    # according to grep, not documented and the only use case I can see is to
193+    # raise it in custom middleware __init__ to disable the middleware
194+    # temporarily. That can be better achieved with disabling it in settings
195+    # (where it is explicit and visible). If everybody is happy with that, the
196+    # exception should be removed from core.exceptions. See also #7820.
197+    return mw_class()
198+
199+def _middleware_type_from_dicts(mw_type, mw_instance_dict, mw_dict):
200+    mw_instance_list = []
201+    for mw_path in mw_dict.get(mw_type, []):
202+        mw_instance = mw_instance_dict[mw_path]
203+        if not hasattr(mw_instance, 'process_' + mw_type):
204+            raise ImproperlyConfigured("%s middleware needs a 'process_%s' "
205+                    "method, but it's missing from %s." % (mw_type.title(),
206+                        mw_type, mw_path))
207+        mw_instance_list.append(mw_instance)
208+    return mw_instance_list