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
的基本用法
📌 示例:为用户分配角色
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import viewsets, status
from django.contrib.auth.models import Userclass 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/
@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
,但可以指定其他方法:
@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
允许自定义权限和认证策略:
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 只做一件事
❌ 错误示例(混合多个逻辑):
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):
@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)权限控制
确保敏感操作(如修改密码)有适当的权限:
@action(detail=True, methods=['post'], permission_classes=[IsAuthenticated])
def change_password(self, request, pk=None):""" 只有登录用户才能修改密码 """
6. 总结
@action
适用于自定义 API 端点- 避免滥用
update
,拆分独立逻辑 - 更符合 RESTful 设计,使 API 语义清晰
- 可搭配权限、认证等更灵活
👉 结论:@action
是 DRF 中提升代码可读性和 API 设计的重要工具,建议在特定业务场景下使用! 🚀