After discussion with akaarai and mYk on IRC, I have two updated proposals.


OPTION 6:

1. Consume `HttpResponse.content` on first access, so that it can be read 
multiple times and eliminate the current buggy behaviour (e.g. 
`response.content != response.content`) when a generator is passed in as 
content.

2. Create a new `HttpStreamingResponse` class, which has no `.content` 
attribute but instead has `.stream` attribute, and can be iterated only 
once. If it is iterated a second time, an exception will be raised to 
trigger a loud failure.

3. Middleware that ships with Django that can work with streaming 
responses, is updated. E.g. GZipMiddleware can do `if isinstance(response, 
HttpStreamingResponse): response.stream = 
compress_sequence(response.stream)`.

4. The `MIDDLEWARE_CLASSES` takes a new optional syntax that allows project 
authors to nominate certain middleware classes for conditional execution. 
This means we don't need to add Yet Another Setting, but the project author 
-- who is the only person in a position to know what combination of 3rd 
party middleware is incompatible with responses returned by other 3rd party 
views -- is able to conditionally execute middleware classes by listing 
compatible (or incompatible) view functions and response classes.

MIDDLEWARE_CLASSES = (
'some.middleware',
'another.middleware',
('some.conditional.middleware', {
'exclude': ['some.incompatible.view.function', 
'some.incompatible.response.class'],
'include': ['some.compatible.view.function', 
'some.compatible.response.class'],
}),
)

This proposal should be backwards compatible, fix the current buggy 
behaviour for people who pass a generator as content to `HttpResponse` but 
don't explicitly want a streaming response, and allow people who do 
explicitly want a streaming responses to have them.

There may be other use cases for conditionally executing middleware, where 
the decision lies with the project author instead of the middleware author 
(who won't know in advance which apps their middleware will have to work 
with). I haven't tried to think of any.

If people return a `HttpStreamingResponse` from their view, and they have 
enabled some old or 3rd party middleware that doesn't know anything about 
this, and which expects to access `response.content`, the project author 
will *have* to nominate that combination of view/response/middleware as 
incompatible in their `MIDDLEWARE_CLASSES` setting to avoid a loud failure.

Which leads me to my next and favourite option...


OPTION 7:

1-2. As for option 6.

3. Add support for a new middleware method specifically for streaming 
responses. E.g. have middleware authors create a 
`.get_streaming_response()` method if their middleware is able to support 
streaming responses. Only `HttpResponse` objects will be passed to 
`.get_response()` middleware methods, and only `HttpStreamingResponse` 
objects will be passed to `.get_streaming_response()` middleware methods.

4. Add `.get_streaming_response()` methods to middleware that ship with 
Django that are able to support streaming responses, e.g. GZipMiddleware.

This should be backwards compatible. Existing code will behave exactly as 
it does now with the exception that `response.content == response.content` 
will be True, whether a generator was passed in as content or not.

No existing middleware will need to be updated unless they explicitly want 
to add support for the new `HttpStreamingResponse` objects.

It will be much clearer in the documentation what middleware authors need 
to do to support streaming responses (implement a new method, vs add a 
conditional branch of execution in their existing method).

It will be much clearer for project authors to see if a middleware class 
does support streaming responses (check for a `.get_streaming_response()` 
method vs hunting in the docs or inside the `.get_response()` method for a 
conditional branch of execution).

It will be clearer for for developers who want to explicitly stream a 
response (use `HttpStreamingResponse` instead of `HttpResponse`).

In the case of existing response middleware that doesn't care about 
accessing the content of a response, they will continue to work as they do 
now for `HttpResponse` objects, but they will need to be updated if they 
also want to work with `HttpStreamingResponse` objects. In that case, if 
they don't access the response content, `.get_streaming_response()` could 
just be an alias for `.get_response()`.


Cheers.
Tai.

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/django-developers/-/wNAoFyXRuGQJ.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.

Reply via email to