DRF开发出现TypeError: 'type' object is not iterable错误求助
DRF API 出现
'type' object is not iterable 错误排查 我首次开发DRF API,在给Movie模型添加Reviews评分平均值计算函数后,发送GET请求时触发了'type' object is not iterable错误。之前功能都正常,搞不懂为什么Reviews和Actor会出现可迭代相关问题,附上相关代码和报错堆栈,求帮忙解决。
相关代码片段
models.py
from django.db import models from django.contrib.auth import get_user_model import datetime User = get_user_model() class Actor(models.Model): name = models.CharField(max_length=255) first_name = models.CharField(max_length=255) class Movie(models.Model): title = models.CharField(max_length=255) description = models.CharField(max_length=255, default='Description') date = models.DateTimeField(default=datetime.date.today) created_on = models.DateTimeField(auto_now_add = True) actors = models.ManyToManyField(Actor) user = models.ForeignKey(User, on_delete=models.CASCADE) def average_reviews(self): if hasattr(self, '_average_reviews'): return self._average_reviews return self.reviews.aggregate(models.Avg('mark')) class Reviews(models.Model): mark = models.IntegerField(default=5) movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
views.py
from django.shortcuts import render from django.db.models import Avg from rest_framework import viewsets from rest_framework.authentication import BasicAuthentication from rest_framework.permissions import IsAuthenticated from .models import Movie, Actor, Reviews from .serializers import MovieSerializer, ActorSerializer, ReviewsSerializer # Create your views here. class MovieViewSet(viewsets.ModelViewSet): authentication_classes = (BasicAuthentication,) permission_classes = (IsAuthenticated,) serializer_class = MovieSerializer def get_queryset(self): return Movie.objects.all().annotate(_average_reviews=Avg('reviews__mark')) #queryset = Movie.objects.all() class ActorViewSet(viewsets.ModelViewSet): authentication_classes = (BasicAuthentication) permission_classes = (IsAuthenticated,) serializer_class = ActorSerializer, queryset = Actor.objects.all() class ReviewsViewSet(viewsets.ModelViewSet): authentication_classes = (BasicAuthentication) permission_classes = (IsAuthenticated,) serializer_class = ReviewsSerializer, queryset = Reviews.objects.all()
serializers.py
from rest_framework import serializers from .models import Movie, Actor, Reviews class ActorSerializer(serializers.ModelSerializer): class Meta: model = Actor fields = '__all__' class ReviewsSerializer(serializers.ModelSerializer): class Meta: model = Reviews fields = '__all__' class MovieSerializer(serializers.ModelSerializer): actors = ActorSerializer(many=True) average_reviews = serializers.SerializerMethodField() def get_average_reviews(self,obj): return obj.average_reviews() class Meta: model = Movie fields = '__all__'
报错堆栈信息
Traceback (most recent call last): File "/home/qcouderc/.local/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner response = get_response(request) File "/home/qcouderc/.local/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/home/qcouderc/.local/lib/python3.10/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view return view_func(*args, **kwargs) File "/home/qcouderc/.local/lib/python3.10/site-packages/rest_framework/viewsets.py", line 125, in view return self.dispatch(request, *args, **kwargs) File "/home/qcouderc/.local/lib/python3.10/site-packages/rest_framework/views.py", line 492, in dispatch request = self.initialize_request(request, *args, **kwargs) File "/home/qcouderc/.local/lib/python3.10/site-packages/rest_framework/viewsets.py", line 146, in initialize_request request = super().initialize_request(request, *args, **kwargs) File "/home/qcouderc/.local/lib/python3.10/site-packages/rest_framework/views.py", line 394, in initialize_request authenticators=self.get_authenticators(), File "/home/qcouderc/.local/lib/python3.10/site-packages/rest_framework/views.py", line 272, in get_authenticators return [auth() for auth in self.authentication_classes] TypeError: 'type' object is not iterable [13/Sep/2022 14:36:00] "GET /api/reviews/ HTTP/1.1" 500 16564
问题解决
核心错误点
报错直接指向get_authenticators方法的迭代操作,问题出在views.py的ActorViewSet和ReviewsViewSet两个视图集的配置错误:
authentication_classes = (BasicAuthentication):缺少末尾逗号,导致这不是元组而是单个类对象,DRF尝试迭代这个类时触发'type' object is not iterable错误。serializer_class = ActorSerializer,:多了末尾逗号,导致变量变成元组,而DRF需要的是单个序列化器类,会引发后续异常。
修复后的视图集代码
class ActorViewSet(viewsets.ModelViewSet): authentication_classes = (BasicAuthentication,) # 补上逗号,确保是元组类型 permission_classes = (IsAuthenticated,) serializer_class = ActorSerializer # 去掉多余逗号 queryset = Actor.objects.all() class ReviewsViewSet(viewsets.ModelViewSet): authentication_classes = (BasicAuthentication,) # 补上逗号,确保是元组类型 permission_classes = (IsAuthenticated,) serializer_class = ReviewsSerializer # 去掉多余逗号 queryset = Reviews.objects.all()
额外优化建议
Movie模型的average_reviews方法返回的是aggregate生成的字典(格式如{'mark__avg': 4.5}),如果想直接返回数值,可以修改方法:
def average_reviews(self): if hasattr(self, '_average_reviews'): return self._average_reviews avg_result = self.reviews.aggregate(models.Avg('mark')) return avg_result.get('mark__avg') or 0 # 处理无评论场景,返回0或None
内容的提问来源于stack exchange,提问作者Quentin Couderc
相关产品推荐
相关产品推荐

