【后端】【django】Django DRF `@action` 详解:自定义 ViewSet 方法

Django DRF @action 详解:自定义 ViewSet 方法

在 Django REST Framework(DRF)中,@action 装饰器用于为 ViewSet 添加自定义的 API 端点。相比于 update、create 等默认方法,@action 允许我们定义 更加清晰、语义化 的 API 访问路径,使接口更加易读且符合 RESTful 设计原则。


1. @action 的作用

@action 主要用于 自定义 API 端点 ,避免滥用 update、create 等标准方法,使 API 语义更加清晰。例如:

  • POST /users/{id}/assign_roles/ ✅ (自定义用户角色分配接口,语义清晰)
  • POST /users/{id}/change_password/ ✅ (单独的修改密码接口)
  • GET /users/{id}/permissions/ ✅ (查询用户权限)

2. @action 的基本用法

📌 示例:为用户分配角色

python 复制代码
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import viewsets, status
from django.contrib.auth.models import User

class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    @action(detail=True, methods=['post'])
    def assign_roles(self, request, pk=None):
        """
        自定义 API 端点:为用户分配角色
        - `detail=True` 表示该方法针对单个用户(即 /users/{id}/assign_roles/)
        - 仅允许 `POST` 方法
        """
        user = self.get_object()
        roles = request.data.get('roles', [])

        # 处理角色分配逻辑(假设 UserRole 是用户角色关联表)
        UserRole.objects.filter(user=user).delete()
        for role_id in roles:
            UserRole.objects.create(user=user, role_id=role_id)

        return Response({"message": "Roles assigned successfully"}, status=status.HTTP_200_OK)

📌 访问路径

方法 访问路径 说明
POST /users/{id}/assign_roles/ 为用户分配角色

3. @action 的参数

@action 可以接收多个参数,主要有:

(1)detail=True/False

  • detail=True:作用于单个对象,路径格式为 /users/{id}/action_name/
  • detail=False:作用于集合,路径格式为 /users/action_name/
python 复制代码
@action(detail=True, methods=['post'])
def assign_roles(self, request, pk=None): 
    """ /users/{id}/assign_roles/ """
@action(detail=False, methods=['get'])
def active_users(self, request):  
    """ /users/active_users/ """
    active_users = User.objects.filter(is_active=True)
    serializer = self.get_serializer(active_users, many=True)
    return Response(serializer.data)

(2)methods=['get', 'post', 'put', 'patch', 'delete']

@action 默认使用 GET,但可以指定其他方法:

python 复制代码
@action(detail=True, methods=['patch'])
def change_password(self, request, pk=None):  
    """ /users/{id}/change_password/ """
    user = self.get_object()
    new_password = request.data.get('password')
    user.set_password(new_password)
    user.save()
    return Response({"message": "Password updated"}, status=status.HTTP_200_OK)

(3)permission_classes=[...], authentication_classes=[...]

@action 允许自定义权限和认证策略:

python 复制代码
from rest_framework.permissions import IsAdminUser

@action(detail=False, methods=['get'], permission_classes=[IsAdminUser])
def admin_users(self, request):  
    """ /users/admin_users/ 仅管理员可访问 """
    admins = User.objects.filter(is_staff=True)
    serializer = self.get_serializer(admins, many=True)
    return Response(serializer.data)

4. @action 与 update 的区别

方法 作用 访问路径 适用场景
update 更新单个用户 PUT /users/{id}/ 用户资料更新
@action 自定义操作 POST /users/{id}/assign_roles/ 角色分配、修改密码等

📌 最佳实践:

  • 简单的用户信息更新 → 用 update
  • 特定业务操作(如分配角色、修改密码) → 用 @action

5. @action 的最佳实践

✅ (1)单一职责:一个 API 只做一件事

❌ 错误示例(混合多个逻辑):

python 复制代码
def update(self, request, pk=None):
    user = self.get_object()
    user.username = request.data.get('username', user.username)
    user.set_password(request.data.get('password'))
    user.save()

✅ 正确示例(拆分成两个 API):

python 复制代码
@action(detail=True, methods=['patch'])
def change_username(self, request, pk=None):
    user = self.get_object()
    user.username = request.data.get('username', user.username)
    user.save()
    return Response({"message": "Username updated"}, status=status.HTTP_200_OK)

@action(detail=True, methods=['patch'])
def change_password(self, request, pk=None):
    user = self.get_object()
    user.set_password(request.data.get('password'))
    user.save()
    return Response({"message": "Password updated"}, status=status.HTTP_200_OK)

✅ (2)语义化 URL

  • 用户更新资料 → PUT /users/{id}/
  • 分配角色 → POST /users/{id}/assign_roles/
  • 查询活跃用户 → GET /users/active_users/
  • 修改密码 → POST /users/{id}/change_password/

❌ 避免滥用 update 处理多个逻辑!


✅ (3)权限控制

确保敏感操作(如修改密码)有适当的权限:

python 复制代码
@action(detail=True, methods=['post'], permission_classes=[IsAuthenticated])
def change_password(self, request, pk=None):
    """ 只有登录用户才能修改密码 """

6. 总结

  • @action 适用于自定义 API 端点
  • 避免滥用 update,拆分独立逻辑
  • 更符合 RESTful 设计,使 API 语义清晰
  • 可搭配权限、认证等更灵活

👉 结论:@action 是 DRF 中提升代码可读性和 API 设计的重要工具,建议在特定业务场景下使用! 🚀

相关推荐
IT_Octopus4 小时前
【零基础入门 LLM 开发 · Day 13】:LangChain 的对话记忆——Message 对象版
人工智能·python·langchain
2603_965148114 小时前
社区与学习资源:从入门到精通的API选品学习路径
数据库·人工智能·python·学习·数据挖掘
CCblandy6 小时前
令牌桶在 0.9 倍负载超发 19%、固定窗口边界放行 20 个:四种限流算法同构实测
后端·python·算法·性能优化·架构
Cc.Y6 小时前
Java零基础入门:深入Java核心:文件IO与序列化全解
java·开发语言·python
拿本唠嗑AI研究7 小时前
本体工程实战指南:从建模到可维护的完整落地路径
java·人工智能·python·jena·ontology
Smoothcloud润云7 小时前
PyTorch推理服务模型热切换与失败回滚实战:降低版本更新中断
服务器·人工智能·pytorch·python·深度学习·gpu
jsjzsl27 小时前
递归自改进系统(RSI)的本质是自发对称破缺:智能爆炸有界—— AI研发切记盲目投入
人工智能·python·算法
2601_954811827 小时前
机器视觉教学套件选型指南:五维技术参数对比与课程体系评估
python·数码相机
小马不起床8 小时前
零基础玩转 FastAPI_05:后端课程模块
python·fastapi
小王2048 小时前
Day 41:模型注意力机制 — SE / CBAM / ECA
python·深度学习·机器学习