There was some discussion about call-through middlewares recently. The most popular idea was to allow wrapping urls with decorators. This way it would be possible to apply any decorator you want to only part of your views. If you do it on root urls level, then you have something like INNER_DISPATCH.
It would be relatively straightforward to add wrap_request() method to middlewares and make that method call-through. That way you would have OUTER_DISPATCH. Replacing all of the current middelware methods with call-through methods turned out to be hard. I think the url wrapping approach could work really well. But without writing a proof-of-concept it is hard to tell if there are some corner cases that make the idea harder to implement than it seems. See https://groups.google.com/d/topic/django-developers/4TnXsONNEso/discussion for the earlier discussion. - Anssi On Thursday, November 28, 2013 12:45:16 AM UTC+2, Stephen Brooks wrote: > > Hi all, > In the original post > https://groups.google.com/d/topic/django-developers/eJFuiWdobbY/discussionI > presented a problem with the current Django middleware archticture and > how it can lead to "*leaks*" in the handling of responses and exceptions. > I also proposed an alternative architecture in the form of middleware > wrappers. *That is the clean solution*, deprecating and eventually > removing the current middleware class architecture. If that is too radical > or the issue I mentiond about deferred rendering cannot be solved or is too > great to be worked around, I have another idea for consideration by the > community, as outlined below. > > This second approach retains the current middleware class architecture and > has no backward incompatibilities. When an application developer wants the > try, except, finally semantics Django could offer two hooking points - an > outer one, and an inner one, as described below: > > The proposed outer hooking point gives control to an application specified > "settings.OUTER_DISPATCH" function (if specified) before Django does any > middleware processing. This function is passed the request object and a > reference to Django's get_response_inner method (into which the current > code in the get_response method would be moved). It returns a response > object. This outer dispatch function can return a short-circuit response, > or call the passed get_response_inner method which performs the middleware > processing and invokes the view function. After Django middleware has > processed the response, control is returned to the outer dispatch function > which can perform any required response processing, finalization or > exception handling. > > The inner hooking point gives control to an application specified > "settings.INNER_DISPATCH function (if specified), directly before Django > invokes the view function; that is, after it has invoked any middleware > process_request and process_view methods. Django will pass it the request > object, the view function, and any argument list and keyword arguments. It > returns a response object. This inner dispatch function can return a > short-circuit response, or call the view function. Whether the view > function returns the response, or raises an exception, the inner dispatch > function can handle both situations (or allow the exception to propagate > upwards). > > By default (e.g. in global_settings) both OUTER_DISPATCH and > INNER_DISPATCH are initialized to None. > > An application developer wanting to have control over the request handling > at the outer level would do something like: > > In the project settings file: > OUTER_DISPATCH = my_outer_dispatch > > def my_outer_dispatch(request, handle_request): > try: > # Perform some request examination or initialization > # and possibly return a short-circuit response. > > response = handle_request(request) # Pass to Django for middleware > # processing and view function > calling > # Perform any processing on the response object that may be needed > return response > except Exception as e: > # Handle the exception, and re-raise if desired or return > # a response. > finally: > # Place finalization code here. > > > An application developer wanting to have control over the request handling > at the inner level would do womething like: > > INNER_DISPATCH = my_inner_dispatch > > def my_inner_dispatch(request, view_func, *view_args, **view_kwargs): > try: > # Perform some request and/or view_func examination or > initialization > # and possibly return a short-circuit response. > > response = view_func(request, *view_args, **view_kwargs) > # Perform any processing on the response object that may be needed > return response > except Exception as e: > # Handle the exception, and re-raise if desired or return > # a response. > finally: > # Place finalization code here. > > > Changes to Django software to faciliate this: > 1. conf/global_settings.py Add lines: > OUTER_DISPATCH = None > INNER_DISPATCH = None > > 2. core/handlers/base.py > Change to the get_response method: > > def get_response(self, request): > if settings.OUTER_DISPATCH: > return settings.OUTER_DISPATCH(request, > self.get_response_inner) > else: > return self.get_response_inner(request) > > def get_response_inner(self, request): > Place here the code which is currently in get_response with > the following change: > Replace the line 114 which currently contains > response = wrapped_callback(request, *callback_args, > **callback_kwargs) > with: > if settings.INNER_DISPATCH: > response = settings.INNER_DISPATCH(request, wrapped_callback, > *callback_args, **callback_kwargs) > else: > response = wrapped_callback(request, *callback_args, > **callback_kwargs) > > *Conclusion:* > Perhaps not as clean as the first proposed solution ( > https://groups.google.com/d/topic/django-developers/eJFuiWdobbY/discussion), > however, it is fully backward compatible, and provides a way for > application developers to put transaction handling into either outer or > inner dispatch functions with leak-proof semantics. > > Your thoughts please... Any votes for this one? > > Regards, > Stephen Brooks > > -- You received this message because you are subscribed to the Google Groups "Django developers" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/django-developers. To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/5c7a4d6e-2f8e-4043-bb6f-be3ab3dc49da%40googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.
