ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于Python和Django的客户关系管理系统设计与实现

基于Python和Django的客户关系管理系统设计与实现 做开发这些年接过不少课程设计和毕业设计项目客户关系管理系统CRM算是我遇到频率最高的题目之一。今天聊的这套基于Python的客户关系管理系统从题面上看是“设计与开发”实际上项目包里包含了完整源码、精品论文、答辩PPT摆明了是按毕业设计整套配置来的。它的核心业务并不复杂围绕“销售或客服人员如何管理客户”这个场景把潜在客户、跟进记录、联系人、商机状态这些数据统一收拢再提供基础的统计看板方便管理者看团队的客户分布和跟进情况。简单说这就是一套带用户权限的Web业务系统。难点不在功能堆砌而在表结构怎么设计、权限怎么隔离、CRUD怎么做得完整不冗余。这篇文章我就从需求整理、技术选型、数据库设计、核心代码实现到答辩资料准备完整过一遍顺带把我在写这类系统时遇到的坑都列出来。1. 项目概述与设计思路1.1 为什么选Python做客户关系管理系统CRM这个概念在企业里早就不新鲜了说白了就是把公司和客户打交道的过程数据化。对中小企业来说客户资料往往散落在销售的Excel表、微信记录甚至纸质笔记本里人员一变动客户资源就可能跟着流失所以CRM系统的第一价值是把客户资产沉淀下来。放到高校的课程设计和毕业设计里这个题目常年热门原因是它有非常清晰的业务模型老师评审时不用费劲理解再加上功能边界稳定、技术栈自由度高适合一个人在一个学期内完成。从技术选型角度看Python做这类管理系统相当顺手。语法接近自然语言写业务逻辑时基本不会被语言本身卡住Django或Flask又打包好了路由、ORM、模板渲染这些Web开发最常用的组件一个人即可完成从前端页面到后端接口的所有工作。比起用Java全家桶做一套“大而全”的系统Python的敏捷性更适合这种中量级项目也更容易在答辩前把功能打磨完整。我实际写下来这套系统的合理定位应该是“内部销售协同管理平台”而不是大厂那种营销自动化中台。核心角色就三类普通员工也就是销售或客服部门主管以及系统管理员。权限设计上普通员工只能看自己的客户和数据主管可以看团队数据并分配线索管理员则维护账号和基础配置。把这三个角色理清后面的表结构、视图函数和权限控制就都有了依据。1.2 核心需求与功能边界做这类项目最怕一上来就堆功能。我见过不少同学一开始就规划“客户管理加商机管理加工单管理加营销活动加数据分析加日程提醒”最后每个模块都做得很浅答辩时一问细节就露馅。更务实的做法是MVP思路先做四个必选模块其余时间用来打磨质量和准备论文。用户与权限模块登录、注册、角色区分、会话管理。客户模块客户名录、客户详情、联系人、客户分类。跟进模块新增跟进记录、关联客户与商机、下次跟进时间提醒。统计模块按客户状态统计数量、跟进次数排行、团队客户分布、转化漏斗概览。这四个模块做完系统的主线故事是完整的销售登录后看到自己的客户列表点进详情看到历史跟进新增一条跟进时系统记录时间点和内容回到看板页看到最近新增和转化情况。就这一条闭环已经能撑起一篇像样的毕业论文。需求阶段还有一件事值得做把页面清单提前列出来。我通常在数据库设计前先列页面比如登录页、注册页、客户列表页、客户详情页、跟进记录弹窗、统计看板页、用户管理页、个人资料页。每一页对应一个视图函数或类开发时不容易漏页面写论文时还能直接引用这套功能架构。2. 技术选型与开发环境搭建2.1 框架选择Django和Flask怎么取舍Python写Web项目绕不开Django和Flask这两个框架。两个我都实际用过在这套CRM上我更推荐Django理由有三个。Django自带Admin后台这个对开发阶段帮助极大。CRM这类系统的数据管理后台本质上就是标准CRUDDjango Admin几乎不用专门写页面就能完成用户、客户、跟进记录的管理用来调试数据非常方便。Django还内置了ORM和迁移机制配合migrations命令数据库表结构能以纯代码方式管理这在写“数据库设计”章节时尤其好使直接贴代码就能解释清楚。再一个Django的认证系统开箱即用登录、退出、会话、密码哈希都封装好了比自己手动处理要靠谱很多。当然Flask做这个项目也没问题。如果前端打算用Vue写单页应用Flask搭配Django REST Framework更像API后端。但单人开发课程设计前端也要自己搞定用Django模板系统直接渲染页面开发效率反而最高。这里有个经验不要为了技术炫耀选择更复杂的架构这类项目的评分点在于逻辑自洽、工作量达标、系统能稳定跑起来。2.2 Python环境与依赖管理环境方面建议用Python 3.8以上版本配合virtualenv或者conda创建独立环境。Python的版本坑不少Django 4.2 LTS要求Python 3.8以上Django 5.x则要求3.10以上如果直接pip install最新版Django老系统里装的是Python 3.6安装就会直接失败。安装依赖时建议固定版本号不要裸装。我常用的一套组合可以稳定跑通Python 3.10 Django 4.2 LTS PyMySQL python-dotenv echarts / Chart.js有人会问为什么不用最新的Django 5.x。其实5.x也在维护期内但不少第三方插件在4.2上的兼容验证更充分。课程设计项目追求稳定没必要追新。如果数据库选择MySQL建库时注意把字符集设为utf8mb4。这个坑我在真实项目里踩过客户备注里只要出现一个emoji写入就报“Incorrect string value”错误排查半天才发现是字符集的问题。DataGrip里建数据库时我习惯直接带上DEFAULT CHARACTER SET utf8mb4一笔账省去后面很多麻烦。3. 数据库设计围绕业务流的表结构3.1 核心表有哪些CRM系统的数据模型不复杂但字段取舍很关键。按前面提到的四个模块核心表主要有这些User用户表可以直接使用Django自带的auth_user再扩展一张Profile表存真实姓名、岗位、部门。Department部门表部门名称、负责人、创建时间用来支撑团队维度的统计。Customer客户表客户名称、电话、邮箱、状态、负责人、创建人、更新时间、备注。Contact联系人表一个客户可能有多个联系人联系人关联客户ID字段包括姓名、职位、电话、微信。FollowUp跟进记录表关联客户记录跟进方式、跟进内容、下次跟进时间、创建人。BusinessOpportunity商机表扩展项记录商机名称、金额、预计成交时间、阶段。表结构设计的核心原则是尽量不冗余。例如“客户状态”直接在Customer表存一个字符串或整型字段不要为了省事把“已成交客户”单独拆成一张表否则后续统计还要做表关联白白增加复杂度。状态用choices常量定义好前端展示时做映射后端过滤时直接用比关联字典表要轻量得多。3.2 Django模型实现与迁移以Customer为例我会把核心代码写成下面这样为便于展示删减了一部分装饰器和校验逻辑from django.db import models from django.contrib.auth.models import User class Customer(models.Model): STATUS_CHOICES ( (lead, 潜在客户), (intention, 意向客户), (deal, 成交客户), (lost, 流失客户), ) name models.CharField(客户名称, max_length120) phone models.CharField(联系电话, max_length20, blankTrue) email models.EmailField(邮箱, blankTrue) status models.CharField( 客户状态, max_length20, choicesSTATUS_CHOICES, defaultlead ) owner models.ForeignKey( User, verbose_name负责人, on_deletemodels.PROTECT, related_namecustomers ) remark models.TextField(备注, blankTrue) created_at models.DateTimeField(创建时间, auto_now_addTrue) updated_at models.DateTimeField(更新时间, auto_nowTrue) def __str__(self): return self.name这里有三个设计细节值得说明。owner字段指向User且on_delete设为PROTECT意思是如果某个销售账号下面还有客户就不能直接删掉这个账号从数据层面防止客户资料被连带删除。phone字段没有使用专门的PhoneNumberField因为Django不自带得依赖第三方库phonenumbers课程设计里没必要为这个功能引入额外依赖用CharField配合正则校验就够了。updated_at用auto_now每次调用save时会自动更新为当前时间省去手动维护。模型写完后执行迁移python manage.py makemigrations python manage.py migrate迁移文件会记录在app的migrations目录下这也是论文“数据模型版本管理”部分的素材。要导出表结构关系图可以用django-extensions的graph_models命令生成ER图不过中文表名显示需要额外配置我个人更推荐直接截图models.py核心代码放进论文清晰且不容易出错。4. 核心功能模块实现4.1 登录认证与权限控制登录模块看着简单实际上CRM系统里最容易被问倒的是权限控制。Django自带login和logout视图但真实项目中通常要扩展几个点登录后跳转目标、角色区分、页面级访问限制。我习惯直接手写登录视图逻辑很直白from django.contrib.auth import authenticate, login from django.shortcuts import render, redirect def login_view(request): if request.method POST: username request.POST.get(username) password request.POST.get(password) user authenticate(request, usernameusername, passwordpassword) if user is not None: login(request, user) return redirect(dashboard) return render(request, login.html, {error: 用户名或密码错误}) return render(request, login.html)权限控制方面我在Profile模型上增加一个role字段来区分员工与主管再配合Django自带login_required保证业务页面必须登录。主管页面的二次过滤可以用user_passes_test判断当前用户role是否为manager。这里特别注意一点判断角色不要用user.is_staff。is_staff在Django里表示“能否进入Admin后台”调试时如果把普通测试账号勾选了is_staff业务权限就会跟着错乱。我的做法是角色字段独立管理和Django自带布尔字段完全分开。权限逻辑保持清晰答辩时也更好向老师解释。4.2 客户信息管理的增删改查客户模块的核心是列表页加详情页。列表页最关键的是数据过滤普通员工只能看到自己名下的客户主管可以看到整个团队的。from django.views.generic import ListView from .models import Customer class CustomerListView(ListView): model Customer template_name customer/list.html paginate_by 10 def get_queryset(self): qs Customer.objects.all() # 普通员工只看自己的客户主管看整个团队 if self.request.user.profile.role staff: qs qs.filter(ownerself.request.user) # 状态、关键字筛选 status self.request.GET.get(status) if status: qs qs.filter(statusstatus) keyword self.request.GET.get(keyword) if keyword: qs qs.filter(name__icontainskeyword) return qs.order_by(-created_at)这段代码是最典型的数据隔离落地点写论文时值得重点展开。很多人用Django做系统时都忽略了这种行级权限控制实际做出来反而是加分项。新增和编辑客户我会用ModelForm完成。Django表单最大的好处是自动渲染HTML、自动校验字段、自动回显错误几行代码就能得到一个可靠的表单from django import forms from .models import Customer class CustomerForm(forms.ModelForm): class Meta: model Customer fields [name, phone, email, status, remark] widgets { remark: forms.Textarea(attrs{rows: 3}), }为什么课程设计不追求前后端分离到这一步就很直观。Django自己负责表单渲染、提交、校验开发量比Vue加axios写一遍再加Django API写一遍要少一半。单人项目优先考虑交付效率。我还会建议给客户列表增加“导出Excel”功能。如果系统里只有增删改查工作量看起来会单薄。加一个导出功能既实用又带技术含量。用openpyxl库遍历queryset写入Excel大概几十行代码就能完成。4.3 跟进记录与统计看板跟进记录模块的数据结构不复杂但业务逻辑上有一个关键点每次新增跟进后最好把客户状态一并更新。例如销售把客户从“潜在客户”推进到“意向客户”在跟进表单里设置一个状态下拉框保存跟进记录的同时更新Customer.status。这样做的好处是统计看板直接按status分组就能画出漏斗图不用额外写复杂的关联查询。统计看板是整个项目中最出效果的部分推荐用echarts来做。Django视图只需要给前端传JSON数据前端再用图表组件渲染。视图示例from django.db.models import Count from django.http import JsonResponse def dashboard_data(request): user request.user qs Customer.objects.all() if user.profile.role staff: qs qs.filter(owneruser) status_data qs.values(status).annotate(cntCount(id)) return JsonResponse({status_data: list(status_data)})前端用echarts饼图渲染核心配置大致是这个样子var chart echarts.init(document.getElementById(chart)); chart.setOption({ tooltip: { trigger: item }, series: [{ type: pie, radius: [40%, 70%], data: statusData }] });需要注意如果演示环境在教室或答辩现场网络可能访问不了外部CDN。我这里用的是本地static目录里存放的echarts.min.js文件确保局域网环境也能正常出图。5. 测试、部署与答辩资料准备5.1 功能测试和常见Bug课程设计的测试不需要覆盖全套单元测试但至少要把核心流程冒烟跑一遍。我的建议是先走通注册、登录、新增客户、新增跟进、查看统计看板这条主路径再验证权限隔离是否真实生效。方法很简单用一个普通员工账号登录尝试访问另一个员工名下的客户详情页看是否被拒绝。实际开发中我见过最多的Bug有三类这里列成速查表典型问题原因解决办法页面时间比本地时间晚8小时时区设置是UTCsettings.py里设置TIME_ZONE为Asia/Shanghai并按需配置USE_TZ关掉DEBUG后页面没有样式Django默认不提供静态文件服务本地演示保持DEBUGTrue或用whitenoise/nginx托管静态目录写入中文或emoji乱码数据库字符集不是utf8mb4建库时指定utf8mb4连接串带charsetutf8mb4第一条时区问题最隐蔽。如果settings.py里没有配置好TIME_ZONE新增客户时页面会显示UTC时间和本地时间相差8个小时答辩演示时很容易暴露。第二种静态文件问题也很头疼本地调试时用runserver一切正常关掉Debug就崩本质上是静态文件服务机制变了。课程设计答辩阶段我更推荐使用本地runserver并保持DEBUGTrue或者用whitenoise中间件兜底这两种模式都能稳定跑起来。5.2 论文结构与答辩PPT准备要点题目里带了“源码精品论文答辩PPT”说明这套资料是配套好的。论文结构按常规毕业设计目录来组织即可绪论写背景和国内外现状技术章节写Python、Django、MySQL和前端技术栈系统分析写可行性和用例图系统设计写架构和数据表系统实现放页面截图和关键代码分析最后系统测试用测试用例表收尾。这样的结构覆盖了学校要求的“分析、设计、实现、测试”四大环节逻辑也完整。答辩PPT一般按“背景与意义、技术与工具、需求分析、总体设计、功能展示、测试结果、总结展望”来做控制在12到15页。一个强烈建议是演示环节提前录制一段操作视频放在PPT最后一页。现场答辩的电脑大概率没有Python环境打开终端跑Django服务这个动作本身就容易出问题比如依赖没装、数据库没初始化、端口被占用。我见过太多次“源码明明在本地能跑现场就是起不来”的尴尬场景视频兜底能有效降低风险。5.3 从课程设计到真实系统的扩展方向如果学有余力这套系统后续有几个不错的扩展方向。第一引入Redis缓存首页统计看板的查询结果减少每次打开看板时的数据库压力。第二加一个简单的定时任务在跟进时间到期时给销售发送提醒邮件可以选用django-celery-beat。第三把前端升级为Vue3配合Element Plus的单页应用后端通过Django REST Framework提供接口这也是往真实企业级项目演进的方向。这些扩展写到论文的“展望”章节里答辩时说出来会显得思考有深度。最后分享一个很小的经验项目根目录一定要有README.md把运行环境、数据库配置、启动步骤、默认账号密码都写清楚。这不是为了给老师交差更多是给自己留后路。答辩前一周你可能还记得启动命令答辩前一天的凌晨大概率已经忘了。把步骤固化下来能少折腾很多。做这类毕业设计项目重要的不是技术多炫而是能不能在有限时间里把系统跑通、把逻辑讲圆、把资料备齐。这三点做到了答辩基本就稳了。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进