Commits

Jesper Nøhr committed c447474 Merge

Comments (0)

Files changed (5)

 Didier Deshommes for contributing a fix for #58
 Alexander Ljungberg for fixing a bug in the default behavior of `update`
 Gareth Rushgrove for plugging a hole in the JSON callback facility
+Matt Cordes for expanding on the rc.* facilities
         
     @property
     def is_anonymous(self):
-        return handler.is_anonymous
+        return self.handler.is_anonymous
 
     def get_model(self):
         return getattr(self, 'model', None)

piston/resource.py

                 isinstance(result, list) or isinstance(result, QuerySet)):
             fields = handler.list_fields
 
+        status_code = 200
+
+        # If we're looking at a response object which contains non-string
+        # content, then assume we should use the emitter to format that 
+        # content
+        if isinstance(result, HttpResponse) and not result._is_string:
+            status_code = result.status_code
+            # Note: We can't use result.content here because that method attempts
+            # to convert the content into a string which we don't want. 
+            # when _is_string is False _container is the raw data
+            result = result._container
+            
         srl = emitter(result, typemapper, handler, fields, anonymous)
 
         try:
             else: stream = srl.render(request)
 
             if not isinstance(stream, HttpResponse):
-                resp = HttpResponse(stream, mimetype=ct)
+                resp = HttpResponse(stream, mimetype=ct, status=status_code)
             else:
                 resp = stream
 
 from django.core import mail
 from django.contrib.auth.models import User
 from django.conf import settings
+from django.http import HttpRequest
+from django.utils import simplejson
 
 # Piston imports
 from test import TestCase
 from models import Consumer
+from handler import BaseHandler
+from utils import rc
+from resource import Resource
 
 class ConsumerTest(TestCase):
     fixtures = ['models.json']
         expected = "Your API Consumer for example.com has been canceled."
         self.assertEquals(mail.outbox[0].subject, expected)
 
+
+class CustomResponseWithStatusCodeTest(TestCase):
+     """
+     Test returning content to be formatted and a custom response code from a 
+     handler method. In this case we're returning 201 (created) and a dictionary 
+     of data. This data will be formatted as json. 
+     """
+
+     def test_reponse_with_data_and_status_code(self):
+         response_data = dict(complex_response=dict(something='good', 
+             something_else='great'))
+
+         class MyHandler(BaseHandler):
+             """
+             Handler which returns a response w/ both data and a status code (201)
+             """
+             allowed_methods = ('POST', )
+
+             def create(self, request):
+                 resp = rc.CREATED
+                 resp.content = response_data
+                 return resp
+
+         resource = Resource(MyHandler)
+         request = HttpRequest()
+         request.method = 'POST'
+         response = resource(request, emitter_format='json')
+
+         self.assertEquals(201, response.status_code)
+         self.assertTrue(response._is_string, "Expected response content to be a string")
+
+         # compare the original data dict with the json response 
+         # converted to a dict
+         self.assertEquals(response_data, simplejson.loads(response.content))
         except TypeError:
             raise AttributeError(attr)
 
-        return HttpResponse(r, content_type='text/plain', status=c)
+        class HttpResponseWrapper(HttpResponse):
+            """
+            Wrap HttpResponse and make sure that the internal _is_string 
+            flag is updated when the _set_content method (via the content 
+            property) is called
+            """
+            def _set_content(self, content):
+                """
+                Set the _container and _is_string properties based on the 
+                type of the value parameter. This logic is in the construtor
+                for HttpResponse, but doesn't get repeated when setting 
+                HttpResponse.content although this bug report (feature request)
+                suggests that it should: http://code.djangoproject.com/ticket/9403 
+                """
+                if not isinstance(content, basestring) and hasattr(content, '__iter__'):
+                    self._container = content
+                    self._is_string = False
+                else:
+                    self._container = [content]
+                    self._is_string = True
+
+            content = property(HttpResponse._get_content, _set_content)            
+
+        return HttpResponseWrapper(r, content_type='text/plain', status=c)
     
 rc = rc_factory()