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

基于Django REST Framework的权限依赖序列化实现问询

Django REST Framework 按角色返回不同用户数据实现方案

可以通过自定义动态序列化器结合权限控制实现这个需求,核心思路是根据访问者的角色以及与被查询用户的关系,动态调整返回的字段集合。以下是具体实现步骤:

1. 定义用户角色(可选,若已有角色体系可跳过)

首先在自定义用户模型中添加角色字段,用于区分普通用户、版主和管理员:

# models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    ROLE_CHOICES = (
        ('user', '普通用户'),
        ('moderator', '版主'),
        ('admin', '管理员'),
    )
    role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='user')

2. 自定义权限验证类

实现权限逻辑,确保不同角色的用户能访问对应范围的用户数据:

# permissions.py
from rest_framework.permissions import BasePermission

class UserDataPermission(BasePermission):
    def has_object_permission(self, request, view, obj):
        # 管理员拥有所有用户数据的访问权限
        if request.user.role == 'admin':
            return True
        # 版主可访问所有用户数据(后续通过序列化器控制字段)
        if request.user.role == 'moderator':
            return True
        # 普通用户仅能访问自身数据
        return obj == request.user

    def has_permission(self, request, view):
        # 列表视图下,管理员和版主可查看所有用户,普通用户仅能查看自己
        if request.user.role in ['admin', 'moderator']:
            return True
        return view.action == 'retrieve' and request.user.is_authenticated

3. 实现动态字段序列化器

通过重写get_fields方法,根据当前用户角色和被查询对象的关系,动态添加/移除返回字段:

# serializers.py
from rest_framework import serializers
from .models import CustomUser

class DynamicUserSerializer(serializers.ModelSerializer):
    def get_fields(self):
        fields = super().get_fields()
        request = self.context.get('request')
        if not request or not request.user.is_authenticated:
            return {}
        
        current_user = request.user
        target_user = self.instance

        # 管理员返回全部字段
        if current_user.role == 'admin':
            return fields
        
        # 版主移除指定敏感字段(示例为password和phone,可按需调整)
        if current_user.role == 'moderator':
            excluded_fields = ['password', 'phone']
            for field in excluded_fields:
                fields.pop(field, None)
            return fields
        
        # 普通用户查询自身:保留ID、用户名、邮箱
        if target_user == current_user:
            allowed_fields = ['id', 'username', 'email']
            return {field: fields[field] for field in allowed_fields if field in fields}
        # 普通用户查询他人:移除邮箱字段
        else:
            fields.pop('email', None)
            return fields

    class Meta:
        model = CustomUser
        fields = '__all__'

4. 视图层整合

将权限类和序列化器应用到视图中,确保请求上下文传递到序列化器:

# views.py
from rest_framework import viewsets
from .models import CustomUser
from .serializers import DynamicUserSerializer
from .permissions import UserDataPermission

class UserViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = CustomUser.objects.all()
    serializer_class = DynamicUserSerializer
    permission_classes = [UserDataPermission]

    def get_serializer_context(self):
        # 传递request到序列化器上下文,用于角色判断
        context = super().get_serializer_context()
        context['request'] = self.request
        return context

补充说明

  • 如果使用Django内置的Group而非自定义role字段,只需将权限类和序列化器中的current_user.role == 'admin'替换为current_user.groups.filter(name='管理员').exists()即可。
  • 若需要支持写入操作(如更新用户信息),可在序列化器中重写create/update方法,同样根据角色控制可修改的字段。
  • 列表视图中,普通用户默认只能查看自身数据,若需调整可修改has_permission方法的逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 01:36:11