开发者

Django-Piston returning JSON/Dictionary as text/plain whenever I change the response type

开发者 https://www.devze.com 2023-02-02 03:46 出处:网络
I\'m debugging some code written by another programmer that uses django-piston to provide an API that returns Python dictionary objects to the caller via JSON. I\'m following the documentation on pist

I'm debugging some code written by another programmer that uses django-piston to provide an API that returns Python dictionary objects to the caller via JSON. I'm following the documentation on piston here.

I noticed some strange behavior where if I manually set response = rc.CREATED and response.content = my_dict, then the content-type of the response is always text/plain, even if I try to overwrite it with response['Content-Type'] = 'application/json; charset=utf-8'.

Here is some sample code.

class RequestHandler(BaseHandler):
    '''API handler for translation request queries.'''

    # we don't allow updating translation requests
    allowed_methods = ('GET', 'POST', 'DELETE')

    @throttle(MAX_REQUESTS_PER_MINUTE, 60)
    def read(self, request, shortname = None, results = False):
        '''Handles a GET request asking about translation requests.'''
        not_deleted = TranslationRequest.objects.exclude(deleted = True)
        not_deleted = not_deleted.filter(owner = request.user)
        if shortname is None:
            objects = not_deleted.all()
        else:
            try:
                _request_uuid = uuid.UUID(shortname)
                objects = [get_object_or_404(not_deleted, request_id=shortname)]
            except ValueError:
                objects = [get_object_or_404(not_deleted, shortname=shortname)]
        objects = [ RequestHandler.request_to_dict(o, results)
                    for o in objects ]
        if len(objects) == 1:
            objects = objects[0]
        return objects

    @throttle(MAX_REQUESTS_PER_MINUTE, 60)
    def create(self, request, shortname = None, results = False):
        '''Handles a POST request to create a new translation request.'''
        if shortname is not None or results:
            return rc.BAD_REQUEST
        print 'CREATE content-type', request.content_type # DEBUG
        # get the data from the POST request
        postdata = self.flatten_dict(request.POST)
        # ensure that the worker field is present
        postdata['worker'] = postdata.get('worker','')
        # validate POST data using our Django form
        form = TranslationRequestForm(request.user, postdata, request.FILES)
        try:
            if not form.is_valid():
                return rc.BAD_REQUEST
        except KeyError:
            return rc.BAD_REQUEST
        # create a new request object
        new = TranslationRequest()
        new.shortname = form.cleaned_data['shortname']
        new.owner = request.user
        new.worker = form.cleaned_data['worker']
        # create a new worker message
        message = TranslationRequestMessage()
        message.request_id = new.request_id
        message.source_language = form.cleaned_data['source_language']
        message.target_language = form.cleaned_data['target_language']
        message.source_text = u''
        for chunk in request.FILES['source_text'].chunks():
            message.source_text += unicode(chunk, 'utf-8')

        handle = open('{0}/{1}.message'.format(TRANSLATION_MESSAGE_PATH,
                                               new.request_id), 'w+b')
        handle.write(message.SerializeToString())
        handle.close()

        new.save()
        new.start_translation()

        messages.add_message(request, messages.SUCCESS, 'Successfully ' \
                             'started translation request "{0}".'.format(
                                new.shortname))

        # return 201 CREATED
        response = rc.CREATED
        # put the URI of the newly created object into the HTTP header
        # Location field (see RFC 2616)
        response['Content-Type'] = 'application/json; charset=utf-8'
        response['Location'] = reverse('requests', args=[new.request_id + '/'])
        # echo the created object inside the HTTP response
        # NOTE: this overwrites the "Location" header field set above.
        # See p开发者_运维知识库iston.resource.__call__()
        response.content = RequestHandler.request_to_dict(new, include_results=False)
        return response

    @staticmethod
    def request_to_dict ( request, include_results = False ):
        '''Transforms a TranslationRequest object to a Python
        dictionary.'''
        retval = {}
        retval['owner'] = request.owner.username
        retval['shortname'] = request.shortname
        retval['worker'] = request.worker.shortname
        retval['created'] = request.created
        retval['request_id'] = request.request_id
        retval['ready'] = request.is_ready()
        if include_results:
            translation_message = request.fetch_translation()
            if type(translation_message) == TranslationRequestMessage:
                retval['source_language'] = translation_message.source_language
                retval['target_language'] = translation_message.target_language
                retval['result'] = translation_message.target_text
                retval.update( [(x.key, x.value) for x in
                                translation_message.packet_data] )
            else:
                retval['result'] = translation_message
        return retval

Using Wireshark, I see that read() returns JSON correctly.

GET /mt-serverland/dashboard/api/results/?token=7594f0db HTTP/1.1

Host: localhost:8081

Accept-Encoding: identity



HTTP/1.0 200 OK

Date: Sat, 01 Jan 2011 01:05:36 GMT

Server: WSGIServer/0.1 Python/2.6.6

Vary: Authorization

Content-Type: application/json; charset=utf-8



[
    {
    "created": "2010-12-31 17:47:51", 
    "source_language": "eng", 
    "worker": "GoogleWorker", 
    "owner": "admin", 
    "result": "Esta es una prueba.\nEspero que este archivo se traducirá correctamente.", 
    "request_id": "b4ca75a301714a5097ce4daab35d370b", 
    "ready": true, 
    "shortname": "test01", 
    "target_language": "spa"
    }
]

However, when I try to use create(), I get the following response:

HTTP/1.0 201 CREATED

Date: Thu, 30 Dec 2010 18:40:25 GMT

Server: WSGIServer/0.1 Python/2.6.6

Vary: Authorization, Cookie

Content-Type: text/plain

Location: http://localhost:8081/mt-serverland/dashboard/api/requests/6614acd8491e4034bcb9b6a9430e6947/

Set-Cookie:  sessionid=5536e58e88ded4365b536a354d3b8a7d; expires=Thu, 13-Jan-2011 18:40:25 GMT; Max-Age=1209600; Path=/



{'created': datetime.datetime(2010, 12, 30, 19, 40, 25, 282665), 'worker': u'GoogleWorker', 'ready': False, 'request_id': '6614acd8491e4034bcb9b6a9430e6947', 'owner': u'admin', 'shortname': u'1234567'}

If I modify create() to just return the object returned by RequestHandler.request_to_dict(), then the response content is application/json. Any ideas why this may be happening? Thanks!


I ran into a very similar problem. After digging through Piston and Django source I decided to try this and it worked:

resp = rc.CREATED
resp.content = dict(
    attendee_id=attendee.id,
    order_id=order.id,
)
return resp

That yields this in HTTP (some headers removed for brevity).

< HTTP/1.1 201 CREATED
< Date: Thu, 27 Jan 2011 16:59:38 GMT
< Server: WSGIServer/0.1 Python/2.6.5
< Vary: Authorization
< Content-Type: application/json; charset=utf-8
< Transfer-Encoding: chunked
< 
{
    "order_id": 22446505, 
    "attendee_id": 18
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号