Hi all,

In porting decorator_from_middleware to support DEP 5 middleware, I ran
into one stumbling block: TemplateResponse. Normally with old-style
middleware, process_response runs after TemplateResponses have been
rendered. But a view decorator runs immediately wrapping the view, when
TemplateResponses will not have been rendered yet. So
decorator_from_middleware has special support for TemplateResponse -- if
it detects one, rather than calling process_response immediately, it
sets it as an on_render_callback.

But in DEP 5 middleware, request and response processing are not
separable -- they are part of the same function. This is the source of
the benefits of DEP 5: strict in/out layering, the ability to use
context managers in middleware, etc. But it also means that there is no
way to delay just the response-processing portion of the middleware
until after render.

My initial strategy [1] was to simply make middleware authors
responsible for this: a middleware that needed to access
response.content and wanted to be compatible with
decorator_from_middleware would be responsible to detect and handle
unrendered TemplateResponse appropriately.

In discussion in IRC, Florian Apolloner suggested an alternative: change
the implementation of decorator_from_middleware so that instead of
immediately applying all middleware methods as an actual view decorator,
make the decorator simply annotate the view callable with an
`_extra_middleware` list, and then add support for this annotation to
the base handler (effectively making it support per-view middleware).
The handler runs per-view middleware as if it were listed last in
MIDDLEWARE (that is, "closest" to the view). I've implemented this
suggestion in [2]. It has several advantages:

1. It consolidates middleware-handling logic in one place, the handler.
Currently this logic is effectively duplicated in the handler and in
decorator_from_middleware, and I've noticed several bugs in the current
decorator_from_middleware resulting from inconsistencies between the
duplicate implementations (e.g. if process_view or process_exception
returns a response, normally that response passes through
process_response, but in decorator_from_middleware it does not.)
Consolidation of this logic will improve consistency of middleware
behavior when listed in settings vs when applied via decorator.

2. It allows us to apply middleware-decorators in closer to the same way
that normal middleware is applied, e.g. response-handling can happen
after render() is called on TemplateResponses, solving the initial problem.

Possible disadvantages of this approach:

1. In order to avoid immediate breakage of decorator_from_middleware
when used with third-party middleware that don't yet support DEP 5, I've
implemented the new approach as a new function, `middleware_decorator`,
that will replace and deprecate `decorator_from_middleware`. This is
unfortunate churn, but I don't see another good way to be
backwards-compatible.

2. The decorators internal to Django that rely on
decorator_from_middleware (the csrf decorators, cache_page) will be
immediately converted to middleware_decorator, resulting in subtle
behavior differences from the current ones.

3. The new behavior may surprise some people accustomed to the old
behavior, since it means the effect of the middleware decorator won't
occur immediately where the decorator is applied. E.g. if you apply a
middleware decorator to a view, and then another custom view decorator
outside that, the custom view decorator won't see the effects of the
middleware decorator in the actual response (it would only see a new
entry in view_func._extra_middleware).

Thoughts welcome.

Carl

 [1] https://github.com/django/django/pull/6765
 [2] https://github.com/django/django/pull/6805

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/57680303.8080002%40oddbird.net.
For more options, visit https://groups.google.com/d/optout.

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to