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 设计的重要工具,建议在特定业务场景下使用! 🚀