ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Django实战:政府集中采购系统从架构设计到部署上线全解析

Django实战:政府集中采购系统从架构设计到部署上线全解析 做政府集中采购系统那阵子我前后折腾了快三个月。从需求调研到最终交付踩坑无数也沉淀了不少经验。回头看看这套基于Python和Django框架搭建的集中采购管理系统其实挺适合作为政企信息化项目的典型样本——业务流程清晰、权限层级分明、数据关联复杂既考验你对Django模型设计的理解也逼着你去思考真实业务里那些绕不开的细节。这篇文章我就把这个项目的完整设计和实现过程拆开揉碎讲一遍从架构选型到数据库设计从审批流实现到权限控制把能写的关键代码和实操心得都放出来给准备做类似系统的同学一个可以直接抄作业的参考。1. 项目全貌这个系统到底解决了什么问题1.1 需求是怎么一步步拆出来的政府集中采购和普通企业采购最大的区别在于两个字合规。每一笔采购都要有预算依据要有审批留痕要有供应商比价记录要有合同归档环环相扣缺一不可。我接到这个项目的时候对方单位还在用Excel加纸质审批单的方式管理采购流程一年几百个采购项目翻查历史记录全靠人工翻文件夹效率低不说还特别容易出纰漏。所以系统设计的第一原则不是把流程做得有多花哨而是把过程留痕、责任到人、数据可查这三件事做扎实。围绕这个目标我把需求拆成几个核心模块采购计划管理、立项审批、供应商管理、竞价比价、合同管理、履约验收再加上系统基础的用户权限和操作日志。每个模块背后都对应着明确的业务角色。采购经办人负责发起采购需求和立项申请部门负责人做一级审批采购中心负责人做二级审核分管领导做最终批准供应商库管理员维护准入名单财务人员查看合同付款状态。角色一多权限控制就成了重头戏这也是后来我花时间最多的地方。1.2 从零搭建系统模块地图梳理完需求我给自己画了一张模块地图。系统整体分成两大块一块是面向普通用户的业务操作端包括采购立项、审批流转、报价管理、合同登记这些日常功能另一块是面向管理员的后台管理端负责用户管理、角色分配、供应商准入、分类字典维护。业务操作端再往下细分采购立项模块要支持采购类别的多级分类货物、工程、服务三大类下面还能继续挂子类。供应商模块要维护供应商的资质文件、联系方式、供货品类还要记录每次参与报价的历史。合同管理模块则要关联采购项目、供应商、合同金额、签订日期、履约进度这些关键信息。这样拆完系统的边界一下子就清楚了。原本模糊的做个采购系统变成了一个个具体可落地的功能点数据库的表结构设计也有了明确依据。1.3 为什么最终选定了Django技术选型其实没有纠结太久。当时我在Python和Java之间权衡过但考虑到项目周期只有三个月团队主力就是Python开发者最终选定了Django。Django在这个项目上确实有天然优势。自带的Admin后台可以快速搭建管理端界面省掉大量重复的CRUD代码内置的ORM让数据库操作变得非常直接模型定义好之后迁移命令一键搞定表结构用户认证和权限系统也是现成的Group和Permission机制跟我们的角色权限需求非常契合。更关键的是Django的MTV架构让视图逻辑和模板渲染清晰分离后续要调整页面布局或者增加接口改起来都很快。后来有人问我为什么不用FastAPI或者Flask。说实话如果只是做个轻量API服务Flask确实更灵巧但这个项目有大量服务端渲染的页面后台管理界面又多用Django这种全家桶框架反而是最省事的。框架选型这种事真的不是越新越好而是越匹配越好。2. 数据库设计与系统架构先把地基打牢2.1 Django MTV架构在这个项目里怎么落地Django的MTV模式——Model、Template、View——在这个项目里的分工非常明确。Model层定义采购项目、供应商、合同、审批记录这些业务实体的数据结构View层处理业务逻辑比如提交立项时校验预算金额、审批时校验权限角色Template层负责页面渲染把数据库里的数据显示成表格、表单和详情页。实际操作中我发现很多初学者会把业务逻辑一股脑写进View里结果单个视图函数动辄几百行。我的做法是把可复用的业务逻辑抽到Service层也就是在app目录下建一个services.py文件。比如创建采购项目时要校验预算、生成项目编号、记录操作日志这一串动作我封装成一个service函数视图里只需要调用它。模板这块Django模板语法虽然简单但有些坑要提前避开。比如模板里不能直接调用带参数的方法很多逻辑判断得靠自定义模板标签或者提前在视图里处理好。我在项目里写了几个自定义过滤器用来格式化金额、转换时间戳用起来非常顺手。2.2 核心表结构设计的一手经验数据库设计是整个项目最见功力的地方。我用MySQL作为存储一共设计了二十多张表其中几张核心表的结构基本决定了系统的能力边界。采购项目表我称呼它为PurchaseProject字段涵盖项目编号、名称、采购类别、预算金额、经办人、当前状态、审批层级。设计的时候特别注意了状态字段我用的是整型数字0代表草稿1代表待审批2代表审批中3代表审批通过4代表已废。之所以不用字符串直接存状态名是因为后面做条件查询和统计时整型比较的效率要明显优于字符串而且不容易因为大小写或者拼写问题出bug。供应商表Supplier除了基础的企业名称、统一社会信用代码、联系人、联系方式我还加上了准入状态字段。供应商从注册到正式进入采购目录需要一个审核流程所以这个字段特别重要。另外我把供应商的资质文件单独拆了一张表SupplierQualification这样一个供应商对应多份资质文件用外键关联扩展性比把所有文件路径都存在一个字段里强得多。审批记录表ApprovalRecord是留痕功能的核心。这条记录完整记录了审批人、审批时间、审批动作和审批意见所有字段都是只读的。我在设计时没有用update来修改记录而是坚持每次审批都插入一条新记录这样整个审批链条是完整且不可篡改的完全满足审计跟踪的需求。合同信息表Contract则关联了采购项目表和供应商表同时记录合同金额、签订日期、履行期限、当前履约状态。这里我特别注意了金额字段的类型选择没用FloatField而是用DecimalField最大位数和保留小数位数分别设成12和2。用浮点数存金额等到算总价的时候出现0.10.2不等于0.3的问题那时候再改就很费劲了。2.3 状态机思维让采购单流转不再混乱采购项目的状态变化是整个系统的业务核心。从草稿到待审批再到各级审批最后到采购执行和归档每个状态之间的流转都有严格的限制条件。我最初是散落着在各处代码里直接改状态字段但后来发现这样很难维护容易出现状态跳变的问题。于是我改用状态机的思路来管理——定义一个全局的状态流转映射表指定每个状态允许跳转到哪些状态然后写了一个公共的状态变更方法所有状态修改都必须走这个方法省去了大量重复校验代码。状态流转路径大致是这样的草稿状态经办人创建立项申请后保存此时项目还没有正式提交支持编辑和删除。待审批状态经办人确认提交项目进入审批流此时项目只能被撤回或进入审批节点。审批中状态审批流上有多个审批节点比如部门负责人、采购中心负责人、分管领导每个节点只能由对应角色操作。审批通过状态所有审批节点都通过后项目进入采购执行阶段可以发起竞价或直接委托。已归档状态合同履约完成项目整体归档数据变成只读。废标状态单独拎出来一个标记为4。废标场景实际中经常发生比如有效供应商不足三家、预算被追减、技术要求变更所以系统必须支持在多个状态下发起废标操作并记录废标原因。状态机设计好之后后面做审批流功能顺手太多每个视图函数只需要关注当前状态下允许做哪些动作不用再查数据库反复判断。3. 核心功能模块实现从登录到合同履约3.1 用户角色划分与权限控制的深度实践用户权限这块Django自带的auth应用已经提供了User、Group、Permission三个核心模型但直接裸用还是不够贴合业务。我在实现时做了一层封装定义了一个UserProfile模型与User做一对一关联存储部门、职位、工号这些扩展信息。角色方面我预置了五个系统管理员、采购经办人、部门审批人、采购中心人员、供应商操作员。每种角色对应不同的权限组每个权限组关联不同的操作权限。比如采购经办人拥有创建采购项目、编辑草稿、提交审批、查看自己经办项目的权限但没有审批权限部门审批人只能看到流转到自己名下的待办任务。权限校验我在视图层用了两种方式。一种是Django自带的permission_required装饰器适合比较简单的场景另一种是自定义的mixin类在类视图中重写dispatch方法做细粒度校验。实际操作中发现纯靠装饰器处理不了经办人只能操作自己创建的项目这样的行级权限所以我在查询时一定会加上user作为过滤条件例如filter(creatorrequest.user)。这就是行级权限控制光靠装饰器干不了这个必须业务代码配合。3.2 采购立项与审批流实现采购立项是整个采购流程的起点。经办人登录系统后点击新建采购项目填写项目名称、采购类别、预算金额、采购需求说明然后保存成草稿。草稿状态下可以反复修改确认无误后点击提交审批项目状态变成待审批。审批流我采用的是多级审批。这里我没有用django-workflow这类第三方库而是自己实现了一个简单的审批链配置表。审批层级配置表定义了每个采购金额区间对应的审批层级比如10万元以下只需要部门负责人审批10万到50万需要部门负责人和采购中心负责人两级审批50万以上还要加上分管领导。这样设计的好处是灵活审批规则变了改配置表就行不用动代码。视图层处理审批动作时代码大致是这样的逻辑拿到审批记录校验当前用户是否拥有这个节点的审批权限然后根据动作——通过或驳回——更新项目状态和审批记录。驳回时必须在意见框里填写原因这个原因会跟着系统通知一起发给发起人。整个审批流跑通之后我明显感觉到项目完整度提升了一大截。经办人提交申请审批人收到消息提醒审批结果实时更新每一步操作都有日志记录。这种流程化的体验根本不是Excel能给的。3.3 供应商管理与竞价功能要点供应商管理模块包括注册、资质审核、信息变更三个主要环节。供应商操作员注册账号后填写企业基本信息和上传资质文件等待采购中心审核。审核通过后供应商才能参与采购项目的报价。竞价功能是这个系统里相对复杂的一块。采购项目审批通过后经办人可以发起询价单选择一批符合条件的供应商设定报价截止时间。供应商在截止时间前填报价格和交货期系统在截止后自动汇总报价记录经办人根据报价结果进行比价议价。为了避免供应商看到别人的报价后恶意压价我在设计时做了隔离处理。报价截止前供应商只能看到自己的报价记录看不全所有供应商的报价截止后报价自动公开系统按价格从低到高排序展示。这个细节在需求评审时被对方反复强调实际做下来确实也提升了竞价环节的公平性。3.4 合同管理与履约跟踪怎么设计合同管理模块在采购系统里处于收尾环节。项目竞价完成后经办人需要在中标供应商确认后创建合同填写合同编号、合同名称、签订日期、合同金额、履约期限上传合同扫描件然后提交审核。合同数据表的关联关系我花了点心思。一笔合同同时关联采购项目、供应商、经办人三个外键缺一不可。我建了一张合同与验收记录的一对多子表因为一份合同可能要分批次供货、分批次验收。每批货物到货后经办人登记验收结果系统自动更新合同履约进度比如已完成三批、每批金额若干一直到累计金额达到合同总额合同状态自动变为已完成。履约进度自动计算这个功能我用了一个简单的累加逻辑。每次插入验收记录时触发post_save信号重新计算该合同下所有验收记录的总金额与合同金额做比较。当履约金额大于等于合同金额时自动把合同状态从履约中改成已完成。这么做最直观的好处是管理层打开合同列表就能看所有合同的履约进度不用点进详情才知道进行到哪一步了。4. 实操现场关键代码实现与避坑指南4.1 Models设计代码实战模型层是整个系统的基础。我以采购项目表为例展示核心字段的设计思路。这个模型直接对应后面的视图和模板字段多一个少一个都影响全流程。from django.db import models from django.contrib.auth.models import User class PurchaseProject(models.Model): STATUS_DRAFT 0 STATUS_PENDING 1 STATUS_APPROVING 2 STATUS_APPROVED 3 STATUS_REJECTED 4 STATUS_ABORTED 5 STATUS_CHOICES ( (STATUS_DRAFT, 草稿), (STATUS_PENDING, 待审批), (STATUS_APPROVING, 审批中), (STATUS_APPROVED, 已通过), (STATUS_REJECTED, 已驳回), (STATUS_ABORTED, 已废标), ) project_no models.CharField(项目编号, max_length32, uniqueTrue) name models.CharField(项目名称, max_length128) category models.ForeignKey(Category, verbose_name采购类别, on_deletemodels.PROTECT) budget_amount models.DecimalField(预算金额, max_digits12, decimal_places2) applicant models.ForeignKey(User, verbose_name申请人, on_deletemodels.PROTECT, related_namecreated_projects) current_status models.IntegerField(当前状态, choicesSTATUS_CHOICES, defaultSTATUS_DRAFT) create_time models.DateTimeField(创建时间, auto_now_addTrue) update_time models.DateTimeField(更新时间, auto_nowTrue) class Meta: db_table purchase_project ordering [-create_time] def __str__(self): return self.name几个关键点说一下。project_no字段我设置了uniqueTrue项目编号是手工生成的规则是年份部门编码四位流水号比如2024-CG-0001。生成逻辑放在service层用事务锁防止并发重复这块在测试时确实碰到过并发问题加了select_for_update才解决。category字段我用了ForeignKey而且没有设nullTrue因为采购类别是必选项。on_deletemodels.PROTECT这个参数值得强调——当有采购项目引用了某个类别时Django会阻止删除这个类别防止出现孤儿数据。如果项目已经上线运行这个保护机制能避免很多低级错误。4.2 View视图层实现与权限控制代码视图层我主要采用基于类的视图并用Django自带的LoginRequiredMixin做登录校验。一个典型的功能页面比如待办审批列表代码结构是这样的from django.contrib.auth.mixins import LoginRequiredMixin from django.views.generic import ListView from .models import ApprovalRecord, PurchaseProject class PendingApprovalListView(LoginRequiredMixin, ListView): template_name approval/pending_list.html context_object_name projects paginate_by 20 def get_queryset(self): # 只返回需要当前用户审批的项目 pending_ids ApprovalRecord.objects.filter( approverself.request.user, is_processedFalse ).values_list(project_id, flatTrue) return PurchaseProject.objects.filter(id__inpending_ids)这个页面的逻辑是用户在待办中心看到所有等着自己审批的采购项目。因为没有引入复杂的消息队列所以用的是最直接的查询方式——关联审批记录表筛选出当前用户作为审批人且尚未处理的记录。这里有个小坑要提醒大家。Django的 queryset 是惰性求值的所以上面代码中 pending_ids 这段在项目数量大的时候会有性能隐患。如果采购项目有几万条in查询会很吃力。我的优化方案是反过来查——先从审批记录表里筛选出当前用户的未处理记录只取项目ID列表然后再去项目表里做in查询。因为一个用户待审批的记录量级通常很小这样性能就能控制在毫秒级。审批动作的提交我是用一个POST表单实现的视图里先判断当前用户是否具有审批权限然后调service层方法。权限校验代码大概长这样def approve_project(request, project_id): project get_object_or_404(PurchaseProject, pkproject_id) if not request.user.has_perm(purchase.can_approve_project): messages.error(request, 您没有审批权限) return redirect(approval:pending_list) # 调用service层完成状态变更和审批记录写入 approve_service.approve(request.user, project, request.POST.get(comment)) return redirect(approval:pending_list)装饰器has_perm这套组合拳基本覆盖了90%的权限控制场景。剩下10%的复杂场景比如一个用户既是采购经办人又是部门审批人需要根据具体数据判断用哪个角色操作这时候必须自己写额外的查询逻辑没有更省事的路子。4.3 文件上传与静态资源处理细节采购系统里涉及大量文件上传包括需求附件、合同扫描件、供应商资质文件。Django处理文件上传不算复杂但有几个细节处理不好后面会非常头疼。首先是文件存储路径。我按业务类型分子目录合同附件放到media/contract/供应商资质放到media/supplier/需求附件放到media/request/。文件名用UUID重命名避免用户上传相同文件名导致覆盖冲突同时也防止中文文件名在URL中编码混乱。其次是文件格式和大小校验。我在Form表单里定义了一个clean方法限制只能上传PDF、JPG、PNG等常见格式同时把上传大小限制改为10MB。别小看这个校验实际使用中总有人想把几百MB的视频文件传上来没有限制会直接把服务器拖垮。还有一个容易忽略的点是Django的MEDIA_ROOT和MEDIA_URL配置。开发环境下为了让上传的文件能直接在浏览器访问需要在urls.py里加一段静态文件路由。但这段路由到了生产环境一定要去掉换成Nginx直接处理静态文件否则文件访问和上传的性能都会很差。4.4 报表统计与Dashboard的实现思路系统管理端有一个数据驾驶舱页面用来展示采购项目的总体情况。我实现了几个核心指标本月新增采购项目数、累计预算金额、待办审批数量、项目状态分布统计。这些数据分散在多张表里统计逻辑不算复杂但要把展示做得直观还是花了些功夫。Django的ORM提供了aggregate和annotate做统计非常方便。比如统计项目状态分布一行代码就能搞定from django.db.models import Count status_stats PurchaseProject.objects.values(current_status).annotate(countCount(id))拿到这个结果后我在前端用ECharts渲染成饼图。饼图、柱状图、折线图这些图表元素用到极致Dashboard看起来就很专业。从实际使用反馈来看领导层最喜欢这个页面毕竟直观看到整体情况比翻列表高效太多。图表库我选了EChartsCDN引入不存在后端复杂集成的问题。要注意的是传给前端的数据一定是JSON格式日期、金额要格式化好不要把Decimal类型直接扔给JavaScript否则容易出现精度问题。5. 常见问题与排查技巧实录5.1 数据库迁移报错的完整解决路径Django的makemigrations和migrate是日常操作但真不是每次都能一帆风顺。项目开发到中期我曾在修改了模型字段后执行迁移结果报错说字段默认值缺失。原因是新加的字段没有设置default或者nullTrue而表中已经存在历史数据Django没法给旧记录填充这个字段。那次报错提醒我形成了一套固定习惯模型字段如果可能影响历史数据要么设置default要么设置nullTrue。如果忘了Django会提示你选择处理方案这时候千万别图省事选了退出要按提示补上合理的默认值。还有一个高频坑是使用ForeignKey后没设置on_delete参数Django 2.0之后这个是必填项不填直接报错这个跟历史数据无关纯粹是语法规范问题。遇到迁移报错最简单的排查顺序是先看报错信息判断是缺默认值还是缺on_delete然后用makemigrations --dry-run看看SQL会执行什么操作最后在迁移之前备份好数据库。开发阶段还好生产环境一旦迁移失败数据回滚的麻烦能让人崩溃。5.2 并发环境下审批状态错乱的排查系统上线后出现过一次比较隐蔽的bug两个审批人同时对同一个采购项目进行了审批操作结果项目状态更新出现了异常一张审批记录被覆盖了。排查下来问题出在审批方法里缺少锁机制两个请求几乎同时读取了项目当前状态都认为自己是合法的审批操作然后先后写入状态后写覆盖了先写。解决办法是在审批操作的事务中先对项目记录加锁再执行状态更新。Django的select_for_update就是干这个的。加锁之后前一个事务提交之前后一个事务会等待避免了并发更新造成的数据不一致。这个问题虽然只在压力测试时出现但暴露出来的深层教训是任何涉及状态变更的业务操作都要考虑并发场景。虽然平时用户量不大但审批这种操作往往集中在月末季末同一时间多个人同时审批没有锁机制就等着出事故。5.3 文件上传中文文件名乱码的修复供应商上传资质文件时文件名经常是中文比如企业法人营业执照.pdf。在开发环境测试没问题部署到生产环境后发现文件名变成了乱码文件也打不开。排查发现是操作系统字符集配置问题。开发环境是Linux的UTF-8生产环境的系统语言环境可能不是导致Django处理中文文件名时编码错乱。我的解决方案是双管齐下第一在settings.py里强制设置文件存储相关编码第二文件保存时用UUID重命名从根源上避免文件名直接使用用户提交的原始文件名。这样不管用户传什么文件名存储到服务器上都是统一的UUID彻底杜绝乱码问题。UUID重命名看似损失了文件名可读性但为了系统稳定性是值得的。真要追溯原始文件名可以把它作为一个字段存在数据库里前端展示用数据库字段实际存储用UUID两者互不干扰。5.4 查询性能优化与索引设计的实战心得系统使用一段时间后采购项目和审批记录表的数据量快速增长部分列表页面开始出现明显的加载延迟。我用Django Debug Toolbar检查了SQL执行情况发现不少页面存在N1查询问题。典型场景是列表页先查出20条采购项目然后模板里循环显示每个项目的申请人姓名每条循环再查一次用户表。原本2条SQL就能解决的问题变成了21条SQL。解决方法是使用select_related和prefetch_related主动预加载关联数据这样在查询项目时就把申请人、类别等关联对象一次性取出来查询次数降到2条。另外我还给高频查询字段建了数据库索引。比如审批记录表的approver和is_processed字段采购项目表的current_status和create_time字段。这里我建的是复合索引优先保证where条件里最常用的字段顺序。索引不是越多越好写操作频繁的表索引过多会影响插入和更新性能这个度要拿捏好。6. 部署上线与运维细节别在最后一步掉链子6.1 从开发环境到生产环境的配置切换开发阶段用的SQLite部署上线换成了MySQL这个切换比想象中坑多。首先要注意Django的MySQL版本兼容性需要安装mysqlclient或pymysql不同版本驱动对Python版本的要求也不一样。我在部署时选的是mysqlclient性能比pymysql好但编译依赖比较麻烦在服务器上装系统依赖包就折腾了一段时间。settings.py里数据库配置也要做区分。我用了环境变量的方式开发环境和生产环境读取不同的配置避免把生产数据库的密码硬编码到代码库里。DEBUG模式在生产环境务必设为False否则一旦出现异常完整的堆栈信息和配置信息会直接暴露在页面上这对政务系统来说是绝对不能接受的安全隐患。静态文件和上传文件的处理也要切换。开发时Django用runserver自带静态文件服务生产环境必须交给Nginx。我用collectstatic命令把所有静态文件收集到指定目录然后配置Nginx的root指向这个目录上传的媒体文件单独用另一个location块映射到MEDIA_ROOT。这一块如果没配好页面样式全丢图片全挂。6.2 日志记录与安全加固政务采购系统对安全的要求比较高。首先是登录环节我关闭了用户名枚举统一提示用户名或密码错误。Django自带的安全中间件全程开启包括X-Content-Type-Options、X-Frame-Options、CSRF防护等。更实用的安全增强是操作日志模块。我在关键视图函数里加了解析用户操作的统一日志方法记录内容包括操作人、操作时间、操作类型、操作对象、IP地址。这个操作日志跟审批记录表还不一样审批记录是业务数据操作日志是审计数据两者分开存储互不干扰。系统上线后有次审计组来检查就是靠完整的操作日志才顺利通过。还有一个细节是在使用Django Admin时至少要修改默认的admin路径。虽然加了登录保护但默认路径会让攻击者更快定位到管理入口改成相对隐蔽的路径也是一种低成本的安全提升。密码策略方面我用的是Django自带的AUTH_PASSWORD_VALIDATORS强制至少8位、包含数字和字母并禁止了常见弱密码。6.3 备份策略与系统监控数据库备份这块我用了Linux的crontab定时任务每天凌晨两点用mysqldump全量备份保留最近30天的备份文件。备份文件同步到另一台存储服务器防止机器故障导致数据丢失。上传的媒体目录也做了同步备份因为合同扫描件、供应商资质文件都是重要凭证丢了就不是麻烦两个字能概括的。系统监控方面我部署了简单的监控脚本定时检查服务端口是否正常运行、磁盘空间是否充足、数据库连接数是否过高。监控脚本发现异常时给运维邮箱发送告警。这套方案谈不上高大上但对于中小规模的系统来说基本够用了。7. 写代码之外的一些个人体会这个项目做完我自己复盘了一下发现最有价值的其实不是代码本身而是对业务流程的理解程度。系统上线后采购经办人反馈说最实用的功能是审批进度可视化——提交立项后能看到单子走到哪一层了再也不用打电话到处问。一个状态进度条比任何花哨的功能都打动人。我还在系统里加了一个小功能项目编号自动生成并支持模糊查询。经办人只要记得项目编号的某几位数字就能在下拉选择器里快速定位到历史项目。这个功能需求文档里根本没有是我跟用户聊天时捕捉到的痛点最终做出来之后好评率意外地高。后续如果要扩展我建议从这几个方向考虑一是引入消息通知机制审批结果通过站内信、短信等方式实时推送给相关人员二是增加数据可视化分析功能对历年采购数据进行深度统计分析为预算编制提供数据支持三是考虑电子签章对接让合同签署完全线上化。这些方向对应到Django生态分别有django-notifications、Chart.js或ECharts、第三方签章API可以对接每一条路都很清晰。做这类系统技术难度通常不是最大的瓶颈真正考验人的是梳理业务流程和抓住关键细节。很多你觉得应该没问题的地方到了实际使用中就是会出问题。保持耐心多跟业务方聊天多在实际场景里测试系统才会越来越贴近真实使用需求。
返回列表