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.