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

在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:10:00