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

DRF过滤实现:工单消息按主键过滤及专属访问权限控制方案

问题解决方法

1. 按URL传入的工单主键过滤关联消息

DRF的通用视图可以通过重写get_queryset方法,从URL参数中获取工单ID后过滤查询集即可,两个消息视图都需要做对应修改:

class TicketAllMessagesSerializerView(generics.ListAPIView):
    queryset = TicketMessage.objects.all()
    serializer_class = TicketMessageSerializer
    permission_classes = [permissions.IsAuthenticated]

    # 新增过滤逻辑
    def get_queryset(self):
        ticket_pk = self.kwargs.get("pk")
        return super().get_queryset().filter(ticket_id=ticket_pk)


class TicketMessagesSerializerView(generics.ListAPIView):
    queryset = TicketMessage.objects.all()
    serializer_class = TicketMessageSerializer
    pagination_class = TicketMessagesPagination
    permission_classes = [permissions.IsAuthenticated]

    # 新增过滤逻辑
    def get_queryset(self):
        ticket_pk = self.kwargs.get("pk")
        return super().get_queryset().filter(ticket_id=ticket_pk)

如果担心参数命名混淆,也可以把路由中的<int:pk>改为<int:ticket_pk>,对应代码中取参数的key同步修改即可。


2. 工单消息访问权限控制

自定义DRF权限类,匹配三类用户的访问规则后,将权限类绑定到对应视图即可:

第一步:编写自定义权限类

from rest_framework.permissions import BasePermission

class TicketAccessPermission(BasePermission):
    def has_permission(self, request, view):
        ticket_pk = view.kwargs.get("pk")
        # 先校验工单是否存在,避免泄露工单存在性
        try:
            ticket = Ticket.objects.only("user_id", "support_id").get(pk=ticket_pk)
        except Ticket.DoesNotExist:
            return False
        # 匹配三类可访问用户
        return (
            request.user.is_superuser 
            or request.user.id == ticket.user_id 
            or request.user.id == ticket.support_id
        )

第二步:绑定权限到视图

修改两个消息视图的permission_classes配置:

permission_classes = [permissions.IsAuthenticated, TicketAccessPermission]

该权限类也可以复用到工单详情、工单状态修改等其他需要工单权限校验的接口中。


现有代码优化建议
  • 视图逻辑优化:当前TicketSerializerView继承的是ListAPIView,仅支持列表查询,你写的create方法不会生效,若需要支持创建工单,改为继承generics.ListCreateAPIView,同时重写perform_create方法自动绑定当前登录用户为工单创建人,避免前端伪造用户ID提交。
  • 模型字段优化:TicketMessage的read字段改为BooleanField更符合业务语义,type字段的选项用Django内置的TextChoices定义更规范;Ticket模型的user字段related_name命名为user不合理,改为created_tickets更便于反向查询;ImageField不要用空字符串做默认值,改为null=True, blank=True避免存储异常。
  • 序列化器优化:不要统一用fields = '__all__',明确指定返回字段避免敏感信息泄露;TicketMessageSerializer也可以添加SlugRelatedField返回用户名,避免只返回用户ID增加前端适配成本;需要前端提交的外键字段(如工单主题、状态)可以设置可写的SlugRelatedField并指定queryset,允许前端传名称而非ID,接口更友好。
  • 性能优化:TicketAllMessagesSerializerView全量返回工单消息在消息量大时会有性能问题,建议取消该接口,统一用分页接口,特殊场景需要全量的也要限制查询字段、增加数量上限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 17:21:03