Django Rest Framework使用登录令牌无需pk调用PUT接口更新User模型头像
问题根因
你使用的ModelViewSet默认的PUT方法对应带资源ID的详情路由(格式为/upload/<用户pk>/),而你请求的/upload/是列表路由,默认仅支持GET(查列表)、POST(创建资源)方法,所以直接请求/upload/的PUT会返回405方法不允许。
方案1:自定义非详情类action(更推荐,逻辑清晰)
直接在视图类中新增一个不需要传pk的自定义action,专门处理当前登录用户的头像更新:
修改views.py:
from rest_framework import viewsets, status from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.parsers import MultiPartParser from rest_framework.permissions import IsAuthenticated from . import serializers from django.contrib.auth import get_user_model User = get_user_model() class UploadViewset(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = serializers.ImageUploadSerializer parser_classes = [MultiPartParser] # 确保只有登录用户可访问 permission_classes = [IsAuthenticated] # 自定义action,detail=False表示不需要资源id,请求方法设为put @action(methods=['put'], detail=False, url_path='avatar') def update_avatar(self, request): # 直接获取当前登录用户 user = request.user # partial=True支持局部更新,不用传用户模型的所有字段 serializer = self.get_serializer(user, data=request.data, partial=True) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data, status=status.HTTP_200_OK)
修改后请求地址变为/upload/avatar/,PUT请求该地址即可直接更新当前登录用户的头像,无需传任何pk参数。
方案2:重写get_object方法,适配原有路由
如果你不想修改请求地址,要继续用/upload/作为PUT接口地址,可以重写视图的核心方法适配逻辑:
修改views.py:
from rest_framework import viewsets from rest_framework.parsers import MultiPartParser from rest_framework.permissions import IsAuthenticated from . import serializers from django.contrib.auth import get_user_model User = get_user_model() class UploadViewset(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = serializers.ImageUploadSerializer parser_classes = [MultiPartParser] permission_classes = [IsAuthenticated] # 固定返回当前登录用户,忽略url中的pk参数 def get_object(self): return self.request.user # 让列表路由支持PUT方法 def get_http_method_names(self): if self.action == 'list': return ['put'] return super().get_http_method_names() # 把列表路由的PUT请求绑定到默认更新逻辑 def list(self, request, *args, **kwargs): return self.update(request, *args, **kwargs)
修改后直接用PUT请求原有/upload/地址即可完成更新。
注意事项
如果需要返回头像的可访问外链,需确保Django配置了正确的媒体资源路由,序列化器无需额外修改,DRF会自动返回资源的相对/绝对路径。
内容的提问来源于stack exchange,提问作者Neil
相关产品推荐
相关产品推荐

