使用IsAuthenticatedOrReadOnly时匿名用户GET请求API报错求助
问题描述
我正在学习Django,跟随书籍和教程搭建了一个项目,用户可创建Post供他人查看。问题是:未登录用户发起GET请求(如PostListCreate视图)时,虽配置了IsAuthenticatedOrReadOnly权限,API仍崩溃,报错:
TypeError: Field 'id' expected a number but got <django.contrib.auth.models.AnonymousUser object at 0x104d2f760>.
我的Post模型包含models.ForeignKey(User, on_delete=models.CASCADE)字段,怀疑与此相关但不确定。已耗时三小时排查未解决,请问需修改哪些内容才能让未认证用户成功发起GET请求?
相关代码
api/views.py
from rest_framework import generics, permissions from .serializers import PostSerializer from post.models import Post class PostListCreate(generics.ListCreateAPIView): serializer_class = PostSerializer permission_classes = [permissions.IsAuthenticatedOrReadOnly] def get_queryset(self): user = self.request.user return Post.objects.filter(user=user).order_by('-created') def perform_create(self,serializer): serializer.save(user=self.request.user) class PostRetrieveUpdateDestroy(generics.RetrieveUpdateDestroyAPIView): serializer_class = PostSerializer permission_classes = [permissions.IsAuthenticatedOrReadOnly] def get_queryset(self): user = self.request.user return Post.objects.filter(user=user)
model.py
from django.db import models from django.contrib.auth.models import User class Post(models.Model): title = models.CharField(max_length=100) description = models.TextField(blank=True) created = models.DateTimeField(auto_now_add=True) sold = models.BooleanField(default=False) user = models.ForeignKey(User, on_delete=models.CASCADE) def __str__(self): return self.title
解决方法
问题根源在于get_queryset方法:未登录用户的self.request.user是AnonymousUser对象,直接用它作为user字段的过滤条件时,ForeignKey字段需要的是User的ID(数字类型),而不是AnonymousUser对象,因此触发类型错误。
根据需求(未登录用户可查看所有Post,登录用户可查看自己的Post并创建/修改/删除自己的Post),修改如下:
修改后的api/views.py
from rest_framework import generics, permissions from rest_framework.exceptions import PermissionDenied from .serializers import PostSerializer from post.models import Post class PostListCreate(generics.ListCreateAPIView): serializer_class = PostSerializer permission_classes = [permissions.IsAuthenticatedOrReadOnly] def get_queryset(self): # 未登录返回所有Post,登录返回当前用户的Post if self.request.user.is_authenticated: return Post.objects.filter(user=self.request.user).order_by('-created') return Post.objects.all().order_by('-created') def perform_create(self,serializer): serializer.save(user=self.request.user) class PostRetrieveUpdateDestroy(generics.RetrieveUpdateDestroyAPIView): serializer_class = PostSerializer permission_classes = [permissions.IsAuthenticatedOrReadOnly] def get_queryset(self): # 未登录返回所有Post,登录返回当前用户的Post if self.request.user.is_authenticated: return Post.objects.filter(user=self.request.user) return Post.objects.all() def perform_update(self, serializer): # 确保登录用户只能修改自己的Post if serializer.instance.user != self.request.user: raise PermissionDenied("你只能修改自己发布的Post") serializer.save() def perform_destroy(self, instance): # 确保登录用户只能删除自己的Post if instance.user != self.request.user: raise PermissionDenied("你只能删除自己发布的Post")
修改说明
PostListCreate的get_queryset:增加is_authenticated判断,避免AnonymousUser对象导致的类型错误,同时满足未登录用户查看所有Post的需求。PostRetrieveUpdateDestroy的get_queryset:同样增加身份判断,补充perform_update和perform_destroy方法,确保登录用户只能操作自己的Post,符合业务逻辑。- 保留
IsAuthenticatedOrReadOnly权限,确保未登录用户仅能进行GET请求,无法执行创建/修改/删除操作。
内容的提问来源于stack exchange,提问作者tester0001
相关产品推荐
相关产品推荐

