每当我更改响应类型时,Django-Piston 将 JSON/字典返回为文本/纯文本

发布于 2024-10-09 18:14:14 字数 6542 浏览 6 评论 0原文

我正在调试另一位程序员编写的一些代码,该代码使用 django-piston 提供一个 API,通过 JSON 将 Python 字典对象返回给调用者。我正在此处关注有关活塞的文档。

我注意到一些奇怪的行为,如果我手动设置 response = rc.CREATEDresponse.content = my_dict,那么响应的内容类型始终是 text/plain,即使我尝试用 response['Content-Type'] = 'application/json; 覆盖它charset=utf-8'

这是一些示例代码。

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 piston.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

使用 Wireshark,我看到 read() 正确返回 JSON。

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"
    }
]

但是,当我尝试使用 create() 时,得到以下响应:

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'}

如果我修改 create() 只返回 RequestHandler.request_to_dict() 返回的对象,则响应内容为 应用程序/json。任何想法为什么会发生这种情况?谢谢!

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 piston.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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

苍风燃霜 2024-10-16 18:14:14

我遇到了一个非常相似的问题。在深入研究 Piston 和 Django 源代码后,我决定尝试一下,它成功了:

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

在 HTTP 中产生了这个(为了简洁,删除了一些标头)。

< 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
}

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文