Commits

Jesper Nøhr committed b0a1571

adding streaming, requires some middleware, adding that too

  • Participants
  • Parent commits c1dd2f6

Comments (0)

Files changed (4)

File piston/emitters.py

+from __future__ import generators
+
 import types, decimal, types, re, inspect
 
 try:
         """
         raise NotImplementedError("Please implement render.")
         
+    def stream_render(self, request, stream=True):
+        """
+        Tells our patched middleware not to look
+        at the contents, and returns a generator
+        rather than the buffered string. Should be
+        more memory friendly for large datasets.
+        """
+        yield self.render(request)
+        
     @classmethod
     def get(cls, format):
         """

File piston/middleware.py

+from django.middleware.http import ConditionalGetMiddleware
+from django.middleware.common import CommonMiddleware
+
+def compat_middleware_factory(klass):
+    """
+    Class wrapper that only executes `process_response`
+    if `streaming` is not set on the `HttpResponse` object.
+    Django has a bad habbit of looking at the content,
+    which will prematurely exhaust the data source if we're
+    using generators or buffers.
+    """
+    class compatwrapper(klass):
+        def process_response(self, req, resp):
+            if not hasattr(resp, 'streaming'):
+                return klass.process_response(self, req, resp)
+            return resp
+    return compatwrapper
+
+ConditionalMiddlewareCompatProxy = compat_middleware_factory(ConditionalGetMiddleware)
+CommonMiddlewareCompatProxy = compat_middleware_factory(CommonMiddleware)

File piston/resource.py

         # Erroring
         self.email_errors = getattr(settings, 'PISTON_EMAIL_ERRORS', True)
         self.display_errors = getattr(settings, 'PISTON_DISPLAY_ERRORS', True)
-    
+        self.stream = getattr(settings, 'PISTON_STREAM_OUTPUT', False)
+
     def determine_emitter(self, request, *args, **kwargs):
         """
         Function for determening which emitter to use
         srl = emitter(result, typemapper, handler, handler.fields, anonymous)
         
         try:
-            return HttpResponse(srl.render(request), mimetype=ct)
+            """
+            Decide whether or not we want a generator here,
+            or we just want to buffer up the entire result
+            before sending it to the client. Won't matter for
+            smaller datasets, but larger will have an impact.
+            """
+            if self.stream: stream = srl.stream_render(request)
+            else: stream = srl.render(request)
+
+            resp = HttpResponse(stream, mimetype=ct)
+
+            resp.streaming = self.stream
+
+            return resp
         except HttpStatusCode, e:
             return HttpResponse(e.message, status=e.code)
 

File tests/test_project/settings.py

     os.path.join(os.path.dirname(__file__), 'templates'),
 )
 ROOT_URLCONF = 'test_project.urls'
+
+MIDDLEWARE_CLASSES = (
+    'piston.middleware.ConditionalMiddlewareCompatProxy',
+    'piston.middleware.CommonMiddlewareCompatProxy',
+)