You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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")

修改说明

  1. PostListCreate的get_queryset:增加is_authenticated判断,避免AnonymousUser对象导致的类型错误,同时满足未登录用户查看所有Post的需求。
  2. PostRetrieveUpdateDestroy的get_queryset:同样增加身份判断,补充perform_update和perform_destroy方法,确保登录用户只能操作自己的Post,符合业务逻辑。
  3. 保留IsAuthenticatedOrReadOnly权限,确保未登录用户仅能进行GET请求,无法执行创建/修改/删除操作。

内容的提问来源于stack exchange,提问作者tester0001

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 10:50:47