Django Rest Framework 如何阻止用户向他人所有的书籍对象添加章节
实现该权限限制的最佳实践为结合 DRF自定义权限类 + 查询集过滤 + 创建逻辑校验 三层防护,完全符合DRF的设计规范,逻辑可复用且无遗漏:
1. 首先自定义通用的书籍所有者权限类
from rest_framework.permissions import BasePermission, IsAuthenticated from rest_framework.exceptions import PermissionDenied class IsBookOwner(BasePermission): def has_permission(self, request, view): # 先校验用户已登录 return request.user.is_authenticated def has_object_permission(self, request, view, obj): # 针对已存在的章节/书籍对象,校验所有者为当前用户 return obj.book.user == request.user
2. 改造ChapterViewSet,添加全链路权限控制
class ChapterViewSet(viewsets.ModelViewSet): queryset = Chapter.objects.all() serializer_class = serializers.ChapterSerializer model = Chapter # 注入权限类,自动拦截未登录用户以及非所有者的对象操作 permission_classes = [IsAuthenticated, IsBookOwner] def get_queryset(self): # 过滤查询集,用户只能看到自己名下书籍的章节 return super().get_queryset().filter(book__user=self.request.user) def perform_create(self, serializer): # 创建章节前校验所选书籍的归属 target_book = serializer.validated_data.get('book') if target_book.user != self.request.user: raise PermissionDenied("您无权向该书籍添加章节") serializer.save()
补充可选优化:序列化器层校验
如果你希望在所有调用该序列化器创建章节的场景下都自动触发归属校验,可以把校验逻辑放到序列化器中,不需要在视图层重复写:
class ChapterSerializer(serializers.ModelSerializer): class Meta: model = Chapter fields = "__all__" def validate_book(self, value): # 序列化器可以从context中拿到当前请求对象 if value.user != self.context["request"].user: raise serializers.ValidationError("您无权选择该书籍") return value
额外优化点
你原来Book视图中的get_queryset方法可以简化,不需要额外查询一次用户表,直接使用请求携带的用户对象即可,减少一次数据库查询:
def get_queryset(self): return Book.objects.filter(user=self.request.user)
内容的提问来源于stack exchange,提问作者Neil
相关产品推荐
相关产品推荐

