跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
PythonAI大前端

从 Web 到 API 驱动:Django REST Framework 重构智能合同审查系统

综述由AI生成智能合同审查系统从传统 Django 模版架构迁移至前后端分离的 API 驱动架构。通过引入 Django REST Framework 与 Vue 3,解决了前后端耦合度高、交互体验差及接口复用难三大问题。文章对比了两种架构下的代码实现,展示了序列化器定义、API 视图编写及前端异步调用流程。进阶实践涵盖 JWT 认证集成、复杂业务逻辑处理。同时解决了跨域资源共享 (CORS) 配置及文件上传至阿里云 OSS 等挑战,为系统扩展打下基础。

www发布于 2026/4/7更新于 2026/5/1314 浏览
从 Web 到 API 驱动:Django REST Framework 重构智能合同审查系统

1. 我们面临的三个核心问题

在项目初期,我们使用了 Django 原生的模版系统。随着业务复杂度的增加,以下问题日益凸显:

耦合度高:前端页面逻辑(HTML/CSS/JS)与后端业务逻辑(Python View)紧密缠绕。修改一个按钮的样式,可能需要后端开发人员介入修改模版文件;后端修改数据结构,又极易打破前端的渲染逻辑。 交互体验差:传统的 Web 应用是多页应用(MPA)。用户每次点击'下一页'、提交表单或进行筛选,浏览器都需要向服务器请求完整的 HTML 页面并重新加载。这种'白屏 - 加载 - 渲染'的循环无法提供类似原生应用的流畅体验。 接口复用难:模版系统直接返回渲染好的 HTML 字符串。如果未来我们需要开发移动端 App 或微信小程序,现有的视图逻辑完全无法复用,必须重新开发一套返回 JSON 数据的 API。


2. 场景实战:合同列表展示

为了更直观地说明区别,我们以'获取并展示用户合同列表'这一高频场景为例,分别展示两种架构下的代码实现。

2.1 传统 Django 模版系统实现

在传统模式下,后端 View 负责查询数据并将其'填'入 HTML 模版中,浏览器接收到的是最终的 HTML 页面。

后端视图 (Views.py)

# 传统 Django View
from django.shortcuts import render
from .models import Contract

def contract_list(request):
    # 1. 业务逻辑:查询当前用户的未删除合同
    contracts = Contract.objects.filter(
        uploader=request.user,
        is_deleted=False
    ).order_by('-created_at')
    context = {
        'contracts': contracts,
        'username': request.user.username
    }
    # 2. 渲染:将数据与 HTML 模版混合,返回完整的 HTML 页面
    return render(request, 'contract/contract_list.html', context)

前端模版 (contract_list.html)

<!-- Django Template Language (DTL) -->
{% extends "base.html" %}
{% block content %}
<div>
    <h2>{{ username }} 的合同列表</h2>
    <table>
        <>
            
                合同编号
                合同名称
                状态
                操作
            
        
        
            
            {% for contract in contracts %}
            
                {{ contract.contract_no }}
                {{ contract.name }}
                {{ contract.get_status_display }}
                
                    
                    查看
                
            
            {% empty %}
            暂无合同
            {% endfor %}
        
    

{% endblock %}
thead
<tr>
<th>
</th>
<th>
</th>
<th>
</th>
<th>
</th>
</tr>
</thead>
<tbody>
<!-- 逻辑与视图耦合:在 HTML 中写循环 -->
<tr>
<td>
</td>
<td>
</td>
<td>
</td>
<td>
<!-- 每次点击都会触发页面完全刷新 -->
<a href="/contract/{{ contract.id }}/">
</a>
</td>
</tr>
<tr>
<td colspan="4">
</td>
</tr>
</tbody>
</table>
</div>

局限性分析:

强耦合:前端开发人员必须懂 Django 模版({% for contract in contracts %}、{{ }})语法,无法独立使用 Vue/React 等现代工具。 体验卡顿:用户想要按'状态'筛选合同,必须点击按钮 -> 浏览器跳转 -> 服务器查询 -> 返回新 HTML -> 浏览器重绘。整个过程用户会感觉到明显的页面刷新。 接口复用难:如果明天要做 App,我们不能直接返回 HTML 给 App。所以不得不再写一套 API(通常是 JSON 格式),这就意味着同样的数据逻辑(获取文章列表)要写两遍,或者做复杂的判断。


2.2 解耦后的 Django + DRF + 前端分离实现

重构后,

后端仅充当数据提供者(Data Provider),通过 RESTful API 返回 JSON 数据; 前端作为独立应用(Vue 3),负责页面渲染和交互。

第一步:定义序列化器 (Serializers.py)

后端首先定义'如何将数据库对象转换为 JSON 格式'。

# backend/contract/serializers.py
from rest_framework import serializers
from .models import Contract

class ContractListSerializer(serializers.ModelSerializer):
    # 自动处理关联字段,例如获取上传者的用户名
    uploader_name = serializers.CharField(source='uploader.username', read_only=True)
    # 自动获取 choices 字段的显示文本(如 "reviewing" -> "审查中")
    status_display = serializers.CharField(source='get_status_display', read_only=True)

    class Meta:
        model = Contract
        # 明确指定返回给前端的字段,按需获取
        fields = ['id', 'name', 'contract_no', 'status', 'status_display', 'uploader_name', 'updated_at']

第二步:编写 API 视图 (Views.py)

视图不再关注 HTML,只关注数据处理和权限。

# backend/contract/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import permissions
from .models import Contract
from .serializers import ContractListSerializer

class ContractView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        """
        获取合同列表 API
        返回格式:JSON
        """
        # 1. 业务逻辑
        queryset = Contract.objects.filter(
            uploader=request.user,
            is_deleted=False
        ).order_by('-created_at')
        # 2. 序列化:将 QuerySet 转换为 JSON 兼容的字典/列表
        serializer = ContractListSerializer(queryset, many=True)
        # 3. 响应:返回纯数据
        return Response({
            'code': 200,
            'msg': '获取成功',
            'data': serializer.data
        })

第三步:前端异步调用 (Vue 3)

前端完全独立,通过 AJAX (Axios) 请求数据,并在本地动态渲染。

// frontend/src/views/contract/ContractHome.vue
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import request from '@/utils/http-axios'

// 定义纯粹的数据接口,不关心后端实现
interface ContractItem {
    id: number
    name: string
    contract_no: string
    status_display: string
}

const contractList = ref<ContractItem[]>([])
const loading = ref(false)

// 异步获取数据,页面无需刷新
const fetchContracts = async () => {
    loading.value = true
    try {
        const res = await request.get('/api/contracts/')
        if (res.data.code === 200) {
            contractList.value = res.data.data
        }
    } finally {
        loading.value = false
    }
}

onMounted(() => {
    fetchContracts()
})
</script>

<template>
    <div v-loading="loading">
        <div v-for="item in contractList" :key="item.id">
            <h3>{{ item.name }}</h3>
            <p>状态:{{ item.status_display }}</p>
        </div>
    </div>
</template>

重构后的收益:

彻底解耦:后端开发人员只关注 API 文档和数据正确性;前端开发人员可以使用 Vue 生态的所有组件库(如 Element Plus),开发效率大幅提升。 极致体验:页面加载后,切换筛选条件或翻页时,JavaScript 只需请求微小的 JSON 数据并局部更新 DOM,用户几乎感觉不到延迟,实现了'单页应用 (SPA)'的丝滑体验。 一次开发,多端复用:/api/contracts/ 接口返回的是标准的 JSON 数据。

  • Web 端:Vue 解析 JSON 渲染表格。
  • 移动端:iOS/Android App 解析同样的 JSON 渲染原生列表。
  • 第三方集成:合作伙伴可以通过该 API 获取合同状态。 无需为新客户端重写任何后端代码。

3. 进阶技术实践

除了基础的 CRUD 接口,DRF 在处理复杂业务场景时也展现出了强大的灵活性。

3.1 认证升级:集成 JWT 与自定义响应

为了适应前后端分离的无状态特性,我们放弃了传统的 Session 认证,改用 JSON Web Token (JWT)。默认的 JWT 接口只返回 access 和 refresh token,但在实际业务中,我们希望在登录成功后直接返回用户的基本信息(如角色、头像),以减少前端的二次请求。

我们可以通过继承 TokenObtainPairSerializer 来实现自定义响应:

# backend/user/serializers.py
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    def validate(self, attrs):
        data = super().validate(attrs)
        # 获取默认的 token 结果
        # 注入额外的用户信息
        data['user'] = {
            'username': self.user.username,
            'age': self.user.age,
            'role': self.user.role,
            'role_display': self.user.get_role_display()
        }
        return data
3.2 复杂业务逻辑处理:APIView 的灵活性

虽然 DRF 提供了 ModelViewSet 来快速生成标准接口,但对于'合同上传'这种涉及多步操作的复杂业务,我们更倾向于使用 APIView 来获得完全的控制权。

例如,一个上传请求需要同时完成:文件存入 OSS -> 获取签名 URL -> OCR 解析 -> 存入数据库 -> 创建版本记录。

# backend/contract/views.py
class ContractView(APIView):
    parser_classes = [MultiPartParser, FormParser]  # 支持文件上传

    def post(self, request):
        file_obj = request.FILES.get('file')
        # 1. 上传至阿里云 OSS
        oss_object_name = upload_contract(file_obj)
        mock_file_url = get_signed_url(oss_object_name)
        # 2. 调用 OCR 解析合同文本
        contract_text = parse_contract_from_url(mock_file_url)
        # 3. 序列化验证与数据保存
        data = request.data.copy()
        serializer = ContractSerializer(data=data)
        if serializer.is_valid():
            contract = serializer.save(uploader=request.user)
            # 4. 手动创建初始版本记录(原子性操作的一部分)
            ContractVersion.objects.create(
                contract=contract,
                version=1,
                file_url=mock_file_url
                # ...
            )
        return Response({'code': 200, 'msg': '上传成功'})

4. 遇到的挑战与解决方案

在重构过程中,我们也遇到了一些典型的'分离焦虑',以下是我们的解决方案:

挑战一:跨域资源共享 (CORS)

前后端分离后,前端(如 localhost:5173)访问后端(localhost:8000)会遇到浏览器的同源策略限制。

解决方案: 安装 django-cors-headers 中间件,并在 settings.py 中配置 CORS_ALLOWED_ORIGINS,明确允许前端开发服务器的域名访问 API。

挑战二:文件上传与静态资源管理

传统的 Django 静态文件管理(MEDIA_ROOT)在分离架构下不再适用,特别是涉及用户上传的敏感合同文件,直接暴露在文件系统中存在安全隐患且难以扩展。

解决方案: 引入阿里云 OSS 对象存储。后端不再存储物理文件,只负责生成上传凭证或接收文件流转发至 OSS,数据库仅存储文件的 Key 或 URL。前端通过后端返回的临时签名 URL 访问文件,既保证了安全性(链接有时效性),又减轻了应用服务器的带宽压力。


5. 总结

通过引入 Django REST Framework,我们不仅解决了'耦合度高、体验差、复用难'这三大顽疾,更为系统的未来扩展打下了坚实基础。现在,我们的智能合同审查系统拥有了清晰的边界:后端是稳定高效的数据与逻辑中心,前端则是灵活多变的交互界面。

目录

  1. 1. 我们面临的三个核心问题
  2. 2. 场景实战:合同列表展示
  3. 2.1 传统 Django 模版系统实现
  4. 传统 Django View
  5. 2.2 解耦后的 Django + DRF + 前端分离实现
  6. backend/contract/serializers.py
  7. backend/contract/views.py
  8. 3. 进阶技术实践
  9. 3.1 认证升级:集成 JWT 与自定义响应
  10. backend/user/serializers.py
  11. 3.2 复杂业务逻辑处理:APIView 的灵活性
  12. backend/contract/views.py
  13. 4. 遇到的挑战与解决方案
  14. 挑战一:跨域资源共享 (CORS)
  15. 挑战二:文件上传与静态资源管理
  16. 5. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 前端现代化:从传统到现代的技术演进
  • 医疗送药机器人“空间拓扑优化+动态算法决策+多级容错控制”三重链式编程技术解析与应用
  • 深入剖析 Spring 框架:架构、缺陷与演进之路
  • 哈希算法深度解析:原理、实现与安全性实战
  • 大模型分布式训练核心原理与高效调参实战
  • 机器人送料机械手结构与控制设计分析
  • 自然语言处理在医疗健康领域的应用与实战
  • GitNexus 纯本地代码知识图谱与可视化分析方案
  • AI 大模型面试核心知识点与参考答案
  • 从 XMLHttpRequest 到 Fetch API:现代前端网络请求的演进与迁移指南
  • 大语言模型(LLMs)技术原理与应用指南
  • 大模型项目实战:多领域智能应用开发
  • 基于 LangChain 和 ChatGLM 的本地知识库问答系统搭建
  • 大模型微调必要性分析:LoRA 与 RAG 方案对比
  • 基于 SpringAI Alibaba 开发大模型智能体,支持基础版和多模式
  • 轮腿机器人代码调试补充
  • 低代码开发:提升企业应用搭建效率的新方式
  • eBay 商品数据采集实战:基于网页抓取 API 的 Python 接入方案
  • Python 采集《雪中悍刀行》弹幕生成词云实例
  • GitHub 实战指南:版本控制与协作核心

相关免费在线工具

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online