Code

Ticket #730: middleware_ordering_with_path-weight_tuples-backwards-compatible.diff

File middleware_ordering_with_path-weight_tuples-backwards-compatible.diff, 4.6 KB (added by mrts, 6 years ago)

Added backwards-compatibility and uniqueness checks. All tests pass as of r8219. See notes below.

Line 
1Index: django/core/handlers/base.py
2===================================================================
3--- django/core/handlers/base.py        (revision 8219)
4+++ django/core/handlers/base.py        (working copy)
5@@ -1,4 +1,8 @@
6 import sys
7+try:
8+    set
9+except NameError:
10+    from sets import Set as set
11 
12 from django import http
13 from django.core import signals
14@@ -29,34 +33,45 @@
15         self._view_middleware = []
16         self._response_middleware = []
17         self._exception_middleware = []
18-        for middleware_path in settings.MIDDLEWARE_CLASSES:
19-            try:
20-                dot = middleware_path.rindex('.')
21-            except ValueError:
22-                raise exceptions.ImproperlyConfigured, '%s isn\'t a middleware module' % middleware_path
23-            mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:]
24-            try:
25-                mod = __import__(mw_module, {}, {}, [''])
26-            except ImportError, e:
27-                raise exceptions.ImproperlyConfigured, 'Error importing middleware %s: "%s"' % (mw_module, e)
28-            try:
29-                mw_class = getattr(mod, mw_classname)
30-            except AttributeError:
31-                raise exceptions.ImproperlyConfigured, 'Middleware module "%s" does not define a "%s" class' % (mw_module, mw_classname)
32 
33-            try:
34-                mw_instance = mw_class()
35-            except exceptions.MiddlewareNotUsed:
36-                continue
37+        if not settings.MIDDLEWARE_CLASSES:
38+            return
39 
40+        # (middleware_path, weight) tuples in MIDDLEWARE_CLASSES,
41+        # heavier items processed first in outbound methods
42+        # OR just backwards-compatible strings
43+        middleware_list = None
44+        if isinstance(settings.MIDDLEWARE_CLASSES[0], tuple):
45+            # uniqueness test
46+            key_set = list(set([mw[1] for mw in settings.MIDDLEWARE_CLASSES]))
47+            if len(key_set) != len(settings.MIDDLEWARE_CLASSES):
48+                raise ImproperlyConfigured("Middleware outbound ordering "
49+                        "values have to be unique.")
50+
51+            middleware_list = _middleware_list_from_iterable([(mw[1], mw[0])
52+                for mw in settings.MIDDLEWARE_CLASSES])
53+        else:
54+            middleware_list = _middleware_list_from_iterable(enumerate(
55+                settings.MIDDLEWARE_CLASSES))
56+
57+        if not middleware_list:
58+            return
59+
60+        # inbound
61+        for _, mw_instance in middleware_list:
62             if hasattr(mw_instance, 'process_request'):
63                 self._request_middleware.append(mw_instance.process_request)
64             if hasattr(mw_instance, 'process_view'):
65                 self._view_middleware.append(mw_instance.process_view)
66+
67+        # outbound
68+        middleware_list.sort()
69+        middleware_list.reverse()
70+        for _, mw_instance in middleware_list:
71             if hasattr(mw_instance, 'process_response'):
72-                self._response_middleware.insert(0, mw_instance.process_response)
73+                self._response_middleware.append(mw_instance.process_response)
74             if hasattr(mw_instance, 'process_exception'):
75-                self._exception_middleware.insert(0, mw_instance.process_exception)
76+                self._exception_middleware.append(mw_instance.process_exception)
77 
78     def get_response(self, request):
79         "Returns an HttpResponse object for the given HttpRequest"
80@@ -196,3 +211,28 @@
81         return force_unicode(script_url[:-len(environ.get('PATH_INFO', ''))])
82     return force_unicode(environ.get('SCRIPT_NAME', u''))
83 
84+def _middleware_list_from_iterable(middleware_iterable):
85+    middleware_list = []
86+    for middleware_tuple in middleware_iterable:
87+        middleware_path = middleware_tuple[1]
88+        try:
89+            dot = middleware_path.rindex('.')
90+        except ValueError:
91+            raise exceptions.ImproperlyConfigured, '%s isn\'t a middleware module' % middleware_path
92+        mw_module, mw_classname = middleware_path[:dot], middleware_path[dot+1:]
93+        try:
94+            mod = __import__(mw_module, {}, {}, [''])
95+        except ImportError, e:
96+            raise exceptions.ImproperlyConfigured, 'Error importing middleware %s: "%s"' % (mw_module, e)
97+        try:
98+            mw_class = getattr(mod, mw_classname)
99+        except AttributeError:
100+            raise exceptions.ImproperlyConfigured, 'Middleware module "%s" does not define a "%s" class' % (mw_module, mw_classname)
101+
102+        try:
103+            mw_instance = mw_class()
104+        except exceptions.MiddlewareNotUsed:
105+            continue
106+        middleware_list.append((middleware_tuple[0], mw_instance))
107+    return middleware_list
108+