Django DRF返回过滤API对象时报TypeError:'type' object is not iterable
问题描述
使用Django与Django REST Framework搭建活动展示类网站时,对数据库内现有模型做过滤、通过新增API返回过滤后对象遇到问题:直接返回数据库全量对象可正常运行,返回过滤后对象时触发报错 TypeError: 'type' object is not iterable。
当前暂未实现按日期过滤逻辑,先通过status字段测试过滤代码逻辑。
相关代码
models.py
from django.db import models class EventQuerySet(models.QuerySet): def today(self): return self.filter(status="Publish") class EventManager(models.Manager): def get_queryset(self): return EventQuerySet(self.model, using=self._db) def today(self): return self.get_queryset().today() class Event(models.Model): CATEGORY = ( ('Smiles', 'Smiles'), ('Laughter', 'Laughter'), ('Crazy', 'Crazy'), ('Food', 'Food'), ('Outside', 'Outside'), ) STATUS = ( ('Publish', 'Publish'), ('Draft', 'Draft'), ) title = models.CharField(max_length=200, blank=False) status = models.CharField(max_length=200, null=True, choices=STATUS) startDate = models.DateField(blank=True) endDate = models.DateField(blank=True) link = models.CharField(max_length=200, blank=False) category = models.CharField(max_length=200, null=True, blank=True, choices=CATEGORY) objects = models.Manager() date = EventManager() class Meta: unique_together = ('title', 'link') def __str__(self): return self.title
在python manage.py shell中测试上述查询逻辑可正常运行,返回结果示例:
<EventQuerySet [<Event: Positivus Festival 2022>, Central European zone stage in equestrian show jumping "Rīga 2022" >, <Event: Exhibition Dramaturgy of the Landscape>, <Event: Writing Implements of Medieval Riga>, '...(remaining elements truncated)...']>
views.py
代码参考Django官方Manager文档实现:
from events.models import Event from rest_framework import generics from rest_framework.generics import ListAPIView from events.serializers import EventSerializer from django_filters import rest_framework as filters class EventTodayView(ListAPIView): """ API endpoint that allows events to be viewed or edited. """ queryset = Event.date.today() class EventFilter(filters.FilterSet): title = filters.CharFilter(field_name="title", lookup_expr='contains') startDate = filters.DateFilter(field_name="startDate", lookup_expr='gte') endDate = filters.DateFilter(field_name="endDate", lookup_expr='lte') class Meta: model = Event fields = ['title', 'status', 'startDate', 'endDate'] class EventAPIView(generics.ListAPIView): """ API endpoint that allows events to be viewed or edited. """ queryset = Event.objects.all().order_by('startDate') serializer_class = EventSerializer filter_backends = (filters.DjangoFilterBackend,) filterset_class = EventFilter
urls.py
from django.contrib import admin from django.urls import path from events import views urlpatterns = [ path('admin/', admin.site.urls), path('api/', views.EventAPIView.as_view(), name='api'), path('api/today', views.EventTodayView.as_view(), name='api-today') ]
完整报错信息
Internal Server Error: /api/today Traceback (most recent call last): File "D:\Prosjekter\Koding\What's happening\env\lib\site-packages\django\core\handlers\exception.py", line 55, in inner response = get_response(request) File "D:\Prosjekter\Koding\What's happening\env\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "D:\Prosjekter\Koding\What's happening\env\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view return view_func(*args, **kwargs) File "D:\Prosjekter\Koding\What's happening\env\lib\site-packages\django\views\generic\base.py", line 84, in view return self.dispatch(request, *args, **kwargs) File "D:\Prosjekter\Koding\What's happening\env\lib\site-packages\rest_framework\views.py", line 509, in dispatch response = self.handle_exception(exc) File "D:\Prosjekter\Koding\What's happening\env\lib\site-packages\rest_framework\views.py", line 469, in handle_exception self.raise_uncaught_exception(exc) File "D:\Prosjekter\Koding\What's happening\env\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception raise exc File "D:\Prosjekter\Koding\What's happening\env\lib\site-packages\rest_framework\views.py", line 506, in dispatch response = handler(request, *args, **kwargs) File "D:\Prosjekter\Koding\What's happening\env\lib\site-packages\rest_framework\generics.py", line 199, in get return self.list(request, *args, **kwargs) File "D:\Prosjekter\Koding\What's happening\env\lib\site-packages\rest_framework\mixins.py", line 38, in list queryset = self.filter_queryset(self.get_queryset()) File "D:\Prosjekter\Koding\What's happening\env\lib\site-packages\rest_framework\generics.py", line 149, in filter_queryset for backend in list(self.filter_backends): TypeError: 'type' object is not iterable
报错原因
- 直接原因:
EventTodayView未显式指定filter_backends属性,继承使用全局DRF配置的过滤后端时,全局配置的DEFAULT_FILTER_BACKENDS被错误赋值为过滤类本身(type类型),而非可迭代的元组/列表,导致遍历时报错。正常运行的EventAPIView因为显式定义了filter_backends = (filters.DjangoFilterBackend,)覆盖了全局错误配置,所以不受影响。 - 潜在问题:直接在视图类属性层面赋值
queryset = Event.date.today()会导致查询集在服务启动时就被评估固化,后续数据库的数据变更(新增/修改/删除活动)不会被该接口感知,同时可能存在ORM初始化时序问题。 - 缺失配置:
EventTodayView未指定serializer_class,即使修复过滤后端问题,后续也会触发序列化类缺失的报错。
修复方案
1. 修正EventTodayView代码
补全缺失的序列化类配置,重写get_queryset()方法返回动态查询结果,显式指定过滤后端配置避免全局配置影响:
class EventTodayView(ListAPIView): """ API endpoint that returns published events. """ serializer_class = EventSerializer # 该接口不需要额外过滤功能则配置为空元组,需要复用过滤逻辑可参考EventAPIView添加对应配置 filter_backends = () def get_queryset(self): return Event.date.today()
2. 修正全局DRF配置(可选,避免其他接口同类报错)
打开项目settings.py找到REST_FRAMEWORK配置段,检查DEFAULT_FILTER_BACKENDS配置,确保其为可迭代的列表/元组格式,单个元素的元组末尾必须加逗号:
REST_FRAMEWORK = { # 其他原有配置... 'DEFAULT_FILTER_BACKENDS': ( 'django_filters.rest_framework.DjangoFilterBackend', ) }
内容的提问来源于stack exchange,提问作者Erling
相关产品推荐
相关产品推荐

