Django Rest Framework(DRF)接口返回格式转换:列表转字典需求及实现问询
Django Rest Framework(DRF)接口返回格式转换:列表转字典需求及实现问询
看起来你现在遇到的问题是:DRF接口返回的是包含单个数据对象的列表格式,但你期望它能像原Java API那样直接返回单个字典对象,对吧?我来帮你梳理下问题原因和调整方案。
问题场景回顾
- 当前DRF接口返回格式(列表包裹单条数据):
[{ "id": 1, "ind_id": 1, "co_ind": "Some String", "no_ind": "Some String", "ds_ind": "Some String", "ds_not_ind": "", "uni_id": 1, "per_id": [ { "id": 7, "no_per": "Some String", "tip_var": "", "co_per": "Some String", "no_cat": "", "per_id": 7, "uni_id": 1 }, { "id": 9, "no_per": "Some String", "tip_var": "", "co_per": "Some String", "no_cat": "", "per_id": 9, "uni_id": 1 }, ], "co_mod": "Some String" }]
- 期望的Java API风格返回格式(直接返回单条数据字典):
{ "id": 1, "ind_id": 1, "co_ind": "A", "no_ind": "DOMÍCILIOS QUE POSSUEM EQUIPAMENTO TIC", "ds_ind": "Total de domicílios", "ds_not_ind": "", "uni_id": 1, "per_id": [ { "id": 7, "no_per": "Proporção de domicílios que possuem equipamentos TIC", "tip_var": "", "co_per": "DIC_TV", "no_cat": "", "per_id": 7, "uni_id": 1 }, { "id": 9, "no_per": "Proporção de domicílios que possuem equipamentos TIC", "tip_var": "", "co_per": "DIC_RADIO", "no_cat": "", "per_id": 9, "uni_id": 1 }, ], "co_mod": "A" }
问题原因
你用的ModelViewSet默认的list动作会把查询集(哪怕只有一条数据)当成集合来序列化,所以最终返回的是列表格式。你的自定义GetIndFilter过滤后返回的依然是QuerySet类型(即使只有一条数据),所以序列化后还是会被包裹成列表。
解决方案:重写视图的list方法
我们可以在GetIndViewSet里重写list方法,判断是否传入了ind_id参数,并且过滤后的结果只有一条数据,如果满足条件就直接返回单个对象的序列化结果,否则保持默认的列表返回逻辑。
修改后的views.py代码如下:
from rest_framework import viewsets, status from rest_framework.response import Response from .models import Inds from .serializers import IndsSerializer class GetIndViewSet(viewsets.ModelViewSet): queryset = Inds.objects.all() serializer_class = IndsSerializer # 简化原来的自定义Filter,直接在get_queryset里处理参数 def get_queryset(self): queryset = super().get_queryset() ind_id = self.request.query_params.get('ind_id') if ind_id: queryset = queryset.filter(ind_id=ind_id) return queryset def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) ind_id = request.query_params.get('ind_id') # 当传入ind_id且结果只有一条时,返回单个对象 if ind_id and queryset.count() == 1: serializer = self.get_serializer(queryset.first()) return Response(serializer.data) # 其他情况保持默认的列表返回逻辑 page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True) return Response(serializer.data)
额外优化点
- 如果需要处理
ind_id对应结果不存在的情况,可以在判断里加上queryset.exists(),返回404状态码或空字典:
if ind_id: if queryset.exists(): if queryset.count() == 1: serializer = self.get_serializer(queryset.first()) return Response(serializer.data) # 如果ind_id对应多条结果,依然返回列表 else: # 返回404或空字典,根据需求调整 return Response({}, status=status.HTTP_404_NOT_FOUND)
- 原来的自定义
GetIndFilter可以简化掉,直接用get_queryset处理参数更直观。
这样调整后,当你用requests.get(base_url + "get_ind?ind_id={}".format(ind))请求时,接口就会返回单个字典对象,和原Java API的格式一致了。
备注:内容来源于stack exchange,提问作者null92
相关产品推荐
相关产品推荐

