DRF开发Blog API POST请求报AnonymousUser匿名用户错误
问题根因
报错由两个核心问题导致:
- PostViewSet全局配置
permission_classes = permissions.AllowAny时,未登录用户发起POST请求,request.user返回的是Django内置的AnonymousUser实例,不是User模型实例,直接赋值给Post的user外键必然触发类型错误。 - 重写create方法时手动传入
context={'request': request}属于冗余操作,ModelViewSet原生的get_serializer方法已经自动将request对象注入序列化器上下文,手动覆盖context反而可能丢失其他必要上下文参数。
修复步骤
1. 调整接口权限规则
写操作(创建、更新、删除文章)必须要求用户认证通过,读操作(获取文章列表、详情)可以保留匿名访问权限,不要全局使用AllowAny:
from rest_framework import permissions, status from rest_framework.response import Response from rest_framework.viewsets import ModelViewSet from .models import Post from .serializers import PostSerializer class PostViewSet(ModelViewSet): queryset = Post.objects.all() serializer_class = PostSerializer def get_permissions(self): if self.action in ["list", "retrieve"]: # 读接口允许匿名访问 permission_classes = [permissions.AllowAny] else: # 写接口必须登录 permission_classes = [permissions.IsAuthenticated] return [perm() for perm in permission_classes]
2. 修正序列化器配置
PostSerializer的user字段保持read_only属性即可,不需要接收前端传入的用户参数,避免越权篡改文章归属:
from rest_framework import serializers from django.contrib.auth.models import User from .models import Post class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ["id", "username"] class PostSerializer(serializers.ModelSerializer): # 若需要返回完整用户信息用下面这行 user = UserSerializer(read_only=True) # 若仅需要返回用户ID,替换为下面这行即可 # user = serializers.PrimaryKeyRelatedField(read_only=True) class Meta: model = Post fields = ["id", "content", "user"]
3. 简化视图的用户绑定逻辑
不要重写整个create方法,直接重写DRF预留的perform_create钩子绑定登录用户即可,不需要手动传递序列化器上下文:
# 在PostViewSet类中添加该方法 def perform_create(self, serializer): # 权限校验通过后,request.user一定是有效的已认证User实例 serializer.save(user=self.request.user)
如果业务需要必须重写create方法,不要手动覆盖context,直接调用self.get_serializer获取序列化器实例即可:
def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) return Response(serializer.data, status=status.HTTP_201_CREATED)
4. 校验认证配置
因为使用dj-rest-auth,需要在settings.py中配置匹配的认证类,确保登录状态能被正确识别:
REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": [ # 浏览器端Session登录用 "rest_framework.authentication.SessionAuthentication", # 前后端分离Token/JWT认证按需开启 # "rest_framework.authentication.TokenAuthentication", # "dj_rest_auth.jwt_auth.JWTCookieAuthentication", ] }
测试注意事项
- 发起POST创建文章请求前,必须先调用dj-rest-auth的登录接口(默认路径为
/dj-rest-auth/login/)完成认证,浏览器测试会自动携带session cookie,接口工具测试需要手动携带认证Token或Cookie。 - 不要为了测试方便给写接口开AllowAny权限,匿名状态下不存在已认证用户,必然触发赋值错误。
- user字段保持read_only配置,通过perform_create注入登录用户是DRF的标准实践,可彻底避免前端越权传入其他用户ID篡改文章归属的问题。
内容的提问来源于stack exchange,提问作者Shloka Bhalgat
相关产品推荐
相关产品推荐

