在Django中结合django-fsm实现请假流程的类视图方法
嘿,刚好我之前在Django 1.11 + DRF环境下用django-fsm和drf-fsm-transitions做过类似的请假工作流,给你一步步拆解怎么实现基于类的视图:
1. 先确认你的Leave模型基础(呼应你已有的定义)
首先先确认你的模型里已经正确定义了状态字段和转换方法,大概应该是这样(如果还没补全转换方法的话可以参考):
from django.db import models from django.contrib.auth.models import User from django_fsm import FSMIntegerField, transition # 状态常量 LEAVE_STATUS_PENDING = 0 LEAVE_STATUS_APPROVED = 1 LEAVE_STATUS_REJECTED = 2 class Leave(models.Model): applicant = models.ForeignKey(User, on_delete=models.CASCADE) start_date = models.DateField() end_date = models.DateField() reason = models.TextField() status = FSMIntegerField( default=LEAVE_STATUS_PENDING, choices=( (LEAVE_STATUS_PENDING, '待审批'), (LEAVE_STATUS_APPROVED, '已批准'), (LEAVE_STATUS_REJECTED, '已驳回'), ), protected=True # 防止直接修改status字段,必须通过转换方法 ) # 批准转换:只能从待审批状态转到已批准 @transition(field=status, source=LEAVE_STATUS_PENDING, target=LEAVE_STATUS_APPROVED) def approve(self): # 这里可以加批准后的逻辑,比如给申请人发站内信/邮件 pass # 驳回转换:只能从待审批状态转到已驳回 @transition(field=status, source=LEAVE_STATUS_PENDING, target=LEAVE_STATUS_REJECTED) def reject(self): # 驳回后的逻辑,比如记录驳回原因(可以加字段存储) pass
注意给status加protected=True,确保只能通过approve()/reject()方法修改状态,避免直接赋值。
2. 序列化器准备
DRF需要序列化器来处理数据,这里我们需要两个序列化器:一个用于申请的创建和展示,另一个用drf-fsm-transitions提供的工具处理状态转换:
from rest_framework import serializers from .models import Leave from drf_fsm_transitions.serializers import TransitionSerializer # 基础序列化器:处理申请的创建和详情展示 class LeaveSerializer(serializers.ModelSerializer): class Meta: model = Leave fields = ['id', 'applicant', 'start_date', 'end_date', 'reason', 'status'] read_only_fields = ['id', 'status', 'applicant'] # 申请人和状态设为只读,申请人自动赋值 # 状态转换序列化器:自动识别模型中的transition方法 class LeaveTransitionSerializer(TransitionSerializer): class Meta: model = Leave fields = ['transition'] # 只需要传transition字段,比如"approve"或"reject"
TransitionSerializer会自动验证传入的transition值是否合法(是否是模型中定义的转换方法),不用自己写验证逻辑,非常省心。
3. 核心:基于类的视图实现
分三类视图来覆盖所有场景:申请人提交/查看申请,审批人处理申请。
3.1 申请人相关视图
from rest_framework.generics import CreateAPIView, ListAPIView, RetrieveAPIView from rest_framework.permissions import IsAuthenticated from .models import Leave from .serializers import LeaveSerializer # 提交请假申请 class LeaveCreateView(CreateAPIView): serializer_class = LeaveSerializer permission_classes = [IsAuthenticated] # 只有登录用户能提交申请 def perform_create(self, serializer): # 自动把当前登录用户设为申请人 serializer.save(applicant=self.request.user) # 查看申请列表:申请人看自己的,审批人看所有 class LeaveListView(ListAPIView): serializer_class = LeaveSerializer permission_classes = [IsAuthenticated] def get_queryset(self): user = self.request.user # 这里假设你给审批人建了名为"Approvers"的用户组 if user.groups.filter(name="Approvers").exists(): return Leave.objects.all() # 普通用户只能看自己的申请 return Leave.objects.filter(applicant=user) # 查看单个申请详情 class LeaveDetailView(RetrieveAPIView): serializer_class = LeaveSerializer permission_classes = [IsAuthenticated] queryset = Leave.objects.all() # 可选:确保用户只能看自己的申请或审批人能看所有 def get_queryset(self): queryset = super().get_queryset() user = self.request.user if not user.groups.filter(name="Approvers").exists(): queryset = queryset.filter(applicant=user) return queryset
3.2 审批人处理申请的视图
直接用drf-fsm-transitions提供的TransitionView,它已经封装了状态转换的逻辑:
from drf_fsm_transitions.views import TransitionView from rest_framework.permissions import IsAuthenticated from .models import Leave from .serializers import LeaveTransitionSerializer # 自定义权限:只有审批组的用户能访问这个视图 class IsApprover(IsAuthenticated): def has_permission(self, request, view): return super().has_permission(request, view) and request.user.groups.filter(name="Approvers").exists() # 处理请假申请的审批/驳回 class LeaveApprovalView(TransitionView): queryset = Leave.objects.all() serializer_class = LeaveTransitionSerializer permission_classes = [IsApprover] # 可选:额外验证,确保只能处理待审批的申请 def get_object(self): obj = super().get_object() if obj.status != Leave.LEAVE_STATUS_PENDING: raise serializers.ValidationError("只能处理待审批的请假申请!") return obj
这个视图接受POST请求,请求体只需要传{"transition": "approve"}或者{"transition": "reject"},就会自动触发模型对应的转换方法,更新状态。
4. URL配置
把视图映射到URL:
from django.conf.urls import url from .views import ( LeaveCreateView, LeaveListView, LeaveDetailView, LeaveApprovalView, ) urlpatterns = [ # 申请人提交申请 url(r'^leaves/create/$', LeaveCreateView.as_view(), name='leave-create'), # 查看申请列表 url(r'^leaves/$', LeaveListView.as_view(), name='leave-list'), # 查看单个申请详情 url(r'^leaves/(?P<pk>\d+)/$', LeaveDetailView.as_view(), name='leave-detail'), # 审批人处理申请 url(r'^leaves/(?P<pk>\d+)/transition/$', LeaveApprovalView.as_view(), name='leave-transition'), ]
一些额外的小提示
- 可以给
Leave模型加一个approval_note字段,让审批人填写驳回/批准的备注,在转换方法里保存。 - 状态转换后可以用Django信号(
post_save)触发通知逻辑,比如给申请人发邮件。 - 测试的时候可以用DRF的可视化界面,提交POST请求到
/leaves/<pk>/transition/,选择对应的transition值测试状态转换。
内容的提问来源于stack exchange,提问作者Philip Mutua
相关产品推荐
相关产品推荐

