Django REST Framework中get_queryset返回单值/单行报错问题
DRF get_queryset 返回单行数据报错的解决办法
为啥会报错?
get_queryset 必须返回可遍历的对象(比如Django的QuerySet、Python列表),你直接返回单个StockPriceModel实例或者last_price这种float值,视图要遍历结果序列化时自然会报“not iterable”——人家要的是可迭代的集合,你给了单个值/对象,当然不行。
完整代码示例
from rest_framework import viewsets from .models import StockPriceModel from .serializers import StockPriceSerializer class StockPriceViewSet(viewsets.ReadOnlyModelViewSet): serializer_class = StockPriceSerializer def get_queryset(self): user = self.request.user # 从请求参数中获取指定的ticker(假设通过query_params传递) ticker = self.request.query_params.get('ticker') if user.is_superuser: # 超级用户:按ticker去重返回,PostgreSQL直接支持distinct('ticker') return StockPriceModel.objects.all().distinct('ticker') # 兼容MySQL的写法:取每个ticker的最新时间记录 # latest_records = StockPriceModel.objects.values('ticker').annotate(latest_time=Max('timestamp')) # return StockPriceModel.objects.filter( # ticker__in=[item['ticker'] for item in latest_records], # timestamp__in=[item['latest_time'] for item in latest_records] # ) else: if not ticker: # 未传ticker时返回空集合,也可根据业务需求抛出异常 return StockPriceModel.objects.none() # 未认证用户:返回指定ticker的最新一行,用[:1]返回含单个对象的QuerySet(可迭代) return StockPriceModel.objects.filter(ticker=ticker).order_by('-timestamp')[:1] # 另一种写法:拿到单个实例后包装成列表 # try: # latest_obj = StockPriceModel.objects.filter(ticker=ticker).latest('timestamp') # return [latest_obj] # except StockPriceModel.DoesNotExist: # return []
关键修复点
- 超级用户去重逻辑:用
distinct('ticker')(PostgreSQL)或annotate取最新记录的方式,确保返回的是可迭代的QuerySet。 - 未认证用户返回单行:
- 别用
.get()、.last()、.latest()直接返回单个实例,这些都不可迭代; - 优先用
.order_by('-timestamp')[:1]返回仅含一条数据的QuerySet,既能满足可迭代要求,还能保留QuerySet的延迟加载等特性; - 若必须用
.latest()获取单个实例,一定要把它放进列表(比如[latest_obj]),转换成可迭代结构; - 直接返回
last_price这个float值是错误的,要么返回包含该值的模型实例,要么通过重写视图方法单独处理字段返回。
- 别用
若仅需返回last_price字段
如果未认证用户只需要last_price而非完整模型数据,可以重写视图的list方法:
from rest_framework.response import Response def list(self, request, *args, **kwargs): queryset = self.get_queryset() if not request.user.is_superuser and queryset.exists(): return Response({'last_price': queryset[0].last_price}) # 超级用户走正常的列表序列化逻辑 return super().list(request, *args, **kwargs)
内容的提问来源于stack exchange,提问作者Sid
相关产品推荐
相关产品推荐

