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 [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/django-developers?hl=en.