【问题标题】:How to correctly serialize API response in Django view如何在 Django 视图中正确序列化 API 响应
【发布时间】:2020-06-24 20:37:26
【问题描述】:

我正在使用另一个 wrapper API 调用 Giphy API,它返回一个字典列表。我很难序列化数据以将其返回给 AJAX。

数据以InlineResponse200 和三个properties 返回。 (docu)

问题是我的视图无法正确返回 JSON:

# Traceback
[2020-06-23 14:58:54,086] log: ERROR - Internal Server Error: /get_gifs/
Traceback (most recent call last):
  File "C:\Users\Jonas\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
    response = get_response(request)
  File "C:\Users\Jonas\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Users\Jonas\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\Jonas\Desktop\finsphere\finsphere\blog\views.py", line 234, in get_gifs
    return JsonResponse(api_response.data[0])
  File "C:\Users\Jonas\AppData\Local\Programs\Python\Python38-32\lib\site-packages\django\http\response.py", line 554, in __init__
    raise TypeError(
TypeError: In order to allow non-dict objects to be serialized set the safe parameter to False.
[23/Jun/2020 14:58:54] "POST /get_gifs/ HTTP/1.1" 500 17874

如果我添加safe=False,它会返回TypeError: Object of type Gif is not JSON serializable

我不明白,因为api_response.data[0] 是一本清晰的字典。

期望的结果:获取登录到Ajax成功函数的Giphy对象。

AJAX

(function($) {
  $('#btnSearch').on('click', function(e) {
      var query = $('#search').val();
      console.log(query);
      e.preventDefault();
      $.ajax({
        type: 'post',
        async: true,
        url: '/get_gifs/',
        data: {
          'query': query,
          'csrfmiddlewaretoken': window.CSRF_TOKEN // from blog.html
        },
        success: function(response) {

        },
        error: function(xhr, status, error) {
          // shit happens friends!
        }
    });
  });
}(jQuery));

(插入我原来的 -free- API 密钥进行复制)
Views.py

def get_gifs(request):

        # create an instance of the API class
        api_instance = giphy_client.DefaultApi()

        # API Key
        api_key = 'NGSKWrBqtIq1rFU1Ka11D879Y1u4Igia'

        # Search term
        q = request.POST.get('query')
        print(q)

        # Query parameters
        limit = 2
        offset = 0
        rating = 'g'
        lang = 'en'
        fmt = 'json'

        try:
            # Search Endpoint
            api_response = api_instance.gifs_search_get(api_key, q, limit=limit, offset=offset, rating=rating, lang=lang, fmt=fmt)
            pprint(api_response)
        except ApiException as e:
            print("Exception when calling DefaultApi->gifs_search_get: %s\n" % e)

        return JsonResponse(api_response.data[0])

API 获取的对象(pprint api_response)

{'data': [{'bitly_gif_url': 'https://gph.is/g/EJWjdvN',
           'bitly_url': 'https://gph.is/g/EJWjdvN',
           'content_url': '',
           'create_datetime': None,
           'embed_url': 'https://giphy.com/embed/J0JGg6doLfmV0yZmIB',
           'featured_tags': None,
           'id': 'J0JGg6doLfmV0yZmIB',
           'images': {'downsized': {'height': '250',
                                    'size': '350582',
                                    'url': 'https://media3.giphy.com/media/J0JGg6doLfmV0yZmIB/giphy.gif?cid=ecefd82565bc1664c2b17e3e4b60d88c736d0c6b5a39d682&rid=giphy.gif',
                                    'width': '478'},
                      'downsized_large': {'height': '250',
                                          'size': '350582',
                                          'url': 'https://media3.giphy.com/media/J0JGg6doLfmV0yZmIB/giphy.gif?cid=ecefd82565bc1664c2b17e3e4b60d88c736d0c6b5a39d682&rid=giphy.gif',
                                          'width': '478'},
                      'preview_gif': {'height': '134',
                                      'size': '49623',
                                      'url': 'https://media3.giphy.com/media/J0JGg6doLfmV0yZmIB/giphy-preview.gif?cid=ecefd82565bc1664c2b17e3e4b60d88c736d0c6b5a39d682&rid=giphy-preview.gif',
                                      'width': '256'}},
           'import_datetime': '2020-06-15 10:01:39',
           'is_anonymous': None,
           'is_community': None,
           'is_featured': None,
           'is_hidden': None,
           'is_indexable': None,
           'is_realtime': None,
           'is_removed': None,
           'is_sticker': False,
           'rating': 'g',
           'slug': 'MITEF-mitefarab-asc2020-J0JGg6doLfmV0yZmIB',
           'source': 'www.mitefarab.org',
           'source_post_url': 'www.mitefarab.org',
           'source_tld': '',
           'tags': None,
           'trending_datetime': '0000-00-00 00:00:00',
           'type': 'gif',
           'update_datetime': None,
           'url': 'https://giphy.com/gifs/MITEF-mitefarab-asc2020-J0JGg6doLfmV0yZmIB',
           'user': {'avatar_url': 'https://media2.giphy.com/avatars/MITEF/8FTlysEjtXzx.jpg',
                    'banner_url': '',
                    'display_name': 'MITEF Pan Arab',
                    'profile_url': 'https://giphy.com/MITEF/',
                    'twitter': None,
                    'username': 'MITEF'},
           'username': 'MITEF'},
          {'bitly_gif_url': 'https://gph.is/g/ZdxQQpP',
           'bitly_url': 'https://gph.is/g/ZdxQQpP',
           'content_url': '',
           'create_datetime': None,
           'embed_url': 'https://giphy.com/embed/hTJF0O4vDkJsUi1h8Q',
           'featured_tags': None,
           'id': 'hTJF0O4vDkJsUi1h8Q',
           'images': {'downsized': {'height': '480',
                                    'size': '310971',
                                    'url': 'https://media3.giphy.com/media/hTJF0O4vDkJsUi1h8Q/giphy.gif?cid=ecefd82565bc1664c2b17e3e4b60d88c736d0c6b5a39d682&rid=giphy.gif',
                                    'width': '480'},                      
                      'preview': {'height': '480',
                                  'mp4': 'https://media3.giphy.com/media/hTJF0O4vDkJsUi1h8Q/giphy-preview.mp4?cid=ecefd82565bc1664c2b17e3e4b60d88c736d0c6b5a39d682&rid=giphy-preview.mp4',
                                  'mp4_size': '15536',
                                  'width': '480'},
                      'preview_gif': {'height': '480',
                                      'size': '22387',
                                      'url': 'https://media3.giphy.com/media/hTJF0O4vDkJsUi1h8Q/giphy-preview.gif?cid=ecefd82565bc1664c2b17e3e4b60d88c736d0c6b5a39d682&rid=giphy-preview.gif',
                                      'width': '480'}},
           'import_datetime': '2019-07-19 22:27:40',
           'is_anonymous': None,
           'is_community': None,
           'is_featured': None,
           'is_hidden': None,
           'is_indexable': None,
           'is_realtime': None,
           'is_removed': None,
           'is_sticker': False,
           'rating': 'g',
           'slug': 'RecargaPay-cashback-recargapay-paguetudopelocelular-hTJF0O4vDkJsUi1h8Q',
           'source': 'www.recargapay.com.br',
           'source_post_url': 'www.recargapay.com.br',
           'source_tld': '',
           'tags': None,
           'trending_datetime': '0000-00-00 00:00:00',
           'type': 'gif',
           'update_datetime': None,
           'url': 'https://giphy.com/gifs/RecargaPay-cashback-recargapay-paguetudopelocelular-hTJF0O4vDkJsUi1h8Q',
           'user': {'avatar_url': 'https://media0.giphy.com/avatars/RecargaPay/msKTiPaVkvqd.png',
                    'banner_url': 'https://media0.giphy.com/headers/RecargaPay/kg023vdaAaWA.gif',
                    'display_name': 'RecargaPay',
                    'profile_url': 'https://giphy.com/RecargaPay/',
                    'twitter': None,
                    'username': 'RecargaPay'},
           'username': 'RecargaPay'}],
 'meta': {'msg': 'OK',
          'response_id': '65bc1664c2b17e3e4b60d88c736d0c6b5a39d682',
          'status': 200},
 'pagination': {'count': 2, 'offset': 0, 'total_count': 10}}

【问题讨论】:

  • 您是否尝试返回 JSON 响应?
  • @VishalSingh 我试过了,是的。查看第一个代码 sn-p,它引发错误:TypeError: Object of type Gif is not JSON serializable

标签: python django


【解决方案1】:

我检查了你的代码,除了你认为的return JsonResponse(api_response.data[0])之外,一切都是正确的

JsonResponse

第一个参数 data 应该是一个 dict 实例。如果 safe 参数设置为 False,它可以是任何 JSON 可序列化对象。 official documentation link

当你说

1. safe=True

return JsonResponse(api_response.data[0])

TypeError: In order to allow non-dict objects to be serialized set the safe parameter to False.

错误很明显api_response.data[0] is not dict,见第2点错误

2 safe=False

return JsonResponse(api_response.data[0], safe=False)
TypeError: Object of type Gif is not JSON serializable

您提供给 JsonResponse 的数据 api_response.data[0]实际上不是 dict 类型的对象,这就是您在第一点出现错误的原因。

当你说safe=FalseJsonResponse 正在尝试序列化对象但该对象不是 json 可序列化时,你可以回溯错误

File "....\Python\Python38\lib\json\encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type Gif is not JSON serializable

可以跟link看哪个对象可以Json序列化

回到你的错误。

我不明白,因为api_response.data[0] 是一本清晰的字典。

api_responseapi_response.data[0] 的类型

type(api_response)
<class 'giphy_client.models.inline_response_200.InlineResponse200'>
type(api_response.data[0])
<class 'giphy_client.models.gif.Gif'>

您可以关注 giphy_client documentation link 了解更多详情

解决方案

result = api_response.data[0].to_dict()   ## NOTE to_dict function of giphy_client.models.gif.Gif

return JsonResponse(result)

【讨论】:

  • 当之无愧,当之无愧我的朋友。太感谢了!我将尽可能奖励赏金(在 3 小时内)
  • 很高兴知道我的回答对您有所帮助,谢谢! @乔纳斯
【解决方案2】:
render(request, template_name, context=None, content_type=None, status=None, using=None)

render() 结合给定模板和给定上下文字典 并返回带有该呈现文本的 HttpResponse 对象。

您可以使用 Django 默认 JsonResponse 类或 Django REST 框架 Response 类来返回 JSON 响应。

from django.http import JsonResponse
return JsonResponse(data=api_response.data)

from rest_framework.response import Response
return Response(data=api_response.data)

在 ipython shell 上试​​过,效果很好。

In [15]: response = Response(api_response.data[0])                                                                                                                              

In [16]: response                                                                                                                                                               
Out[16]: <Response status_code=200, "text/html; charset=utf-8">

response.data 给我序列化的响应。

【讨论】:

  • 啊,我把课搞砸了,真的。使用 JsonResponse 它仍然说它不是 dict 对象。我更新了我的帖子。
  • @Jonas 在您的情况下使用 Django REST 框架提供的 Response 类。
  • 我尝试了这种方法,但现在出现了不同的错误。我将它添加到最初的帖子中。谢谢!
  • @Jonas 将第一个元素分配给 api_response.data 即api_response.data = data[0] 不是一个好主意,因为正如您所说,您正在使用另一个包装器 API 调用 Giphy API,而您不知道是什么在窗帘后面进行。试试这个return Response(data=api_response.data[0])
  • 引发错误:TypeError: 'type' 类型的对象现在没有 len()
【解决方案3】:

Python 有一个内置函数可以将 dicts 转换为 json。

import json

data = api_response.data
return render(request, json.dumps(data))

如果你在 return 语句中使用它,它应该返回 json。

【讨论】:

    猜你喜欢
    • 2016-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-24
    • 1970-01-01
    • 1970-01-01
    • 2015-04-17
    • 1970-01-01
    相关资源
    最近更新 更多