python写crm_python---CRM用户关系管理
Day1:项目分析一:需求分析二:CRM角色功能介绍三:业务场景分析销售:1.销售A 从百度推广获取了一个客户,录入了CRM系统,咨询了Python课程,但是没有报名2.销售B 从qq群获取一个客户,成功使他报名Python班,然后给他发送了报名连接,等待用户填写完毕后,将他添加到Python具体的学习班级中3.销售C 打电话给之前的一个客户,说服他报名Python课程,但是没有成功,更新了跟踪记
Day1:项目分析
一:需求分析
二:CRM角色功能介绍
三:业务场景分析
销售:
1.销售A 从百度推广获取了一个客户,录入了CRM系统,咨询了Python课程,但是没有报名
2.销售B 从qq群获取一个客户,成功使他报名Python班,然后给他发送了报名连接,等待用户填写完毕后,将他添加到Python具体的学习班级中
3.销售C 打电话给之前的一个客户,说服他报名Python课程,但是没有成功,更新了跟踪记录
4.销售D 获取了一个客户,录入信息时,发现此客户已经存在,不允许重复录入,随后通知相应的原负责人跟进
5.销售E 从客户库中获取了,超过一个月未跟进的客户,进行再次跟进
6.销售主管 查看了部门本月的销售报表,包括来源分析,成单率分析,班级报名数量分析,销售额环比,同比
学员:
1.客户A 填写了销售发来的报名连接,上传了个人的证件信息,提交,之后收到邮件,告知报名成功,并为他开通了学员账号,升级为学员A
2.学员A 登录学员系统,看到自己的合同,报名的班级,课程大纲
3.学员A 提交了Python课程当时课时作业
4.学员A 查看自己的Python课程成绩,排名
5.学员A 搜索问题,未找到答案,录入一条问题
6.学员A 转介绍学员,录入其信息
讲师:
1.讲师A 登录CRM系统,查看自己管理的班级列表
2.讲师A 进入Python 5期课程,创建第3节的上课记录,填写了本节课内容,作业要求
3.讲师A 在课程中点名,对点名情况进行录入,标记相关状态
4.讲师A 批量下载所有学员的课时作业,给每个学员在线批注了成绩+状态
管理员:
1.创建课程 C++,Python..
2.创建校区 上海,北京..
3.创建班级 C++35期,Python27期
4.创建账号 ABCD
5.创建了销售,讲师,学员角色
6.为账号分配到对应的角色,将ABCD分配给销售
7.创建相关权限
8.为销售角色分配了相关权限
四:表结构设计
数据库关联模型
Django表结构实现
表结构创建
Day2:主要实现功能kingadmin为各个应用实现一个类似于Django自带的数据库管理功能
kingadmin目录
销售目录
学员目录
1.首先我们需要在项目启动后(进入Kingadmin模块中view视图后,能够自动采集所有的应用中需要我们采集的数据库信息)
(1)先设置采集方法:在每个需要我们采集的应用模块中添加上kingadmin.py文件(类似于后台admin会在应用模块的admin.py中采集信息一样)。如上面目录结构,在其中添加了kingadmin.py
Sale模块中kingadmin
Student模块中kingadmin
从中发现需要用到一个基类BaseKingAdmin来自于kingadmin模块:是为了防止注册事件时出现为空的现象,而且在基类中添加功能更加方便
admin_base.py中BaseKingAdmin基类
还需要from kingadmin.sites import site,使用到site方法(类似于admin.site.register(模型,自定义模型显示类)):功能是将各个模块中的数据模型统一添加在一个数据结构中,方便调用
sites.py中的site方法
将数据统一放入self.enabled_admins{}中,形式为self.enabled_admins[模块][表名] = 自定义模型显示类(默认BaseKingAdmin)
注意:虽然在每个模块中都导入了一次sites模块,使用一次site对象,实际上使用的是同一个site对象
可以使用id(site)查看内存,因为python机制中将一个模块导入后,会将其保存在内存中,下次导入数据的时候,会直接从内存中获取数据(所以大家使用的是一个site对象)
所以说:python模块本身就是单例模式
(2)从settings.py中获取各个模块。创建app_setup.py文件,在项目进入view时去调用该文件,并执行,获取到所有模块的信息
进入views.py自动调用app_setup.kingadmin_auto_discover()方法
views.py进入后,顺序执行,首先去调用app_setup.kingadmin_auto_discover()方法采集信息
看如何采集各个模块信息:从配置文件中settings的INSTALLED_APPS中获取所有模块信息
settings文件INSTALLED_APPS
views调用了app_setup中的kingadmin_auto_discover()方法自动采集信息,下面看看app_setup文件:实现方法。反向查找
from django import conf #实现动态获取配置文件,而不是以目录形式
import importlib
def kingadmin_auto_discover():
for module in conf.settings.INSTALLED_APPS:
try:
# md = importlib.import_module('.kingadmin',module) #这个也可以
md = __import__('%s.kingadmin'%module) #导入Kingadmin,然后回去执行该文件中的数据,去注册事件(模块导入后,会自动使用site.register方法注册事件)
except ImportError as e:
pass
(3)上面将数据采集完毕,方法内存中site对象中,使用app_index视图方法,可以实现后台管理admin首页功能
def app_index(request):return render(request,"kingadmin/app_index.html",{'site':site})
前端主要代码
(4)实现点击表名,查看数据的功能
table_obj_list方法根据模块和表名去获取site对象中的数据
前端
my_func.py设置自定义函数
Day3:对上面的功能添加分页,筛选,排序,搜索功能(功能之间的url需要重组)
分页类代码
分页类的使用
使用模板函数对分页数据进行url组合
build_page_row模板函数
二:对各个字段筛选(对kingadmin中list_filter字段进行筛选)
1:前端显示
build_filter_row模板函数去获取数据生成标签
2.模板函数去定制标签,在form表单中加入隐藏标签(表示排序和搜索条件)
build_filter_row模板函数对日期筛选进行自定义,外键或者choices字段使用字段对象获取数据,对于其他的字段使用model获取所有的值,组成select框进行筛选
3.在views中将url中的各个条件,放置到admin_class中,方便模板标签的使用
注意:我在views中将各个url条件放在admin_class中,方便查询对比(也可以放在变量中分发出来)
4.在views中的url数据获取时将其他_q搜索,o排序,_p分页数据过滤,获取所有数据
get_filter_result过滤条件,获取querysets数据
三:对各个字段进行排序(list_display)
1.前端传递排序数据,对于table中的th加上url
使用模板函数处理
2.模板函数build_title_row 去生成标签
build_title_row中先将过滤和搜索条件组合,再生成排序url(符号倒序,数字代表在admin_class中list_display字段中的索引顺序)
3.views中对我们获取的所有数据,根据前端传递的排序方法进行排序处理
get_order_result获取排序结果
四:对字段进行搜索(search_fields)
1.前端生成标签时,form表单中需要一起传递其他条件的input隐藏框
前端数据form
2.使用模板函数生成标签
build_search_filter模板函数,生成input标签(含有各个条件)
3.后端处理搜索条件,生成querysets数据
views处理搜索字段,注意使用OR,需要用到Q方法
Day4:动态生成任意表的CURD
1.如何在前端动态生成标签?使用form验证可以针对model生成所有的字段控件
实验:使用固定的数据模型去生成对应的form验证类,可以用来在前端之间生成控件
2.如何针对每张表动态生成一个Form类?需要用到type方法去动态生成类
form_handle.py中去创建方法,动态创建类
3.在修改页面中动态创建Form类(需要传递原来数据)
table_obj_change方法去创建form类,传递到前端
url中对于修改的匹配
4.在添加页面动态创建Form类
table_obj_add方法
url.py中对于添加的匹配
添加的url
5.修改和添加的HTML和公共部分
table_obj_add.html
table_obj_change.html
table_obj_change_component.html公共部分
6.处理在add和change中对于readonly_fileds字段的不同
在动态生成ModelForm修改,并且向admin_class.add_flag加入标识,前端进行判别,决定是否去显示只读字段
7.对于filter_horizontal字段我们在模板函数中进行获取所有的值,并且判断是否显示在哪一个select标签中
前端对filter_horizontal进行判别,针对两个select都进行判别,一个放置选中一个放置未选中
get_rel_m2m_val模板函数获取关联对象得所有值,用到字段对象的related_model属性获取关联对象
get_rel_m2m_sel方法判断是否数据被选中,返回True选中,放在第二个select标签,放在未选中,放在第一个select标签
8.实现js双击option,在两个select之间跳转
为两个select标签绑定同一个MoveEleToOpp方法
MoveEleToOpp方法实现:通过判断父标签select的id,将当前option转移append到对方的select中
9.实现在点击保存时,form表单自动将右侧select中的数据全部选中。注意:加上name为select标签,name="字段名"
为form表单绑定方法ChangeSelStatus
ChangeSelStatus实现
10.为filter_horizontal完善功能,添加全选,全部移除
前端HTML
ChooseAll函数js代码
Day5:删除功能开发和action方法实现
1.删除功能开发
前端HTML代码
模板函数,去递归生成标签
views后台删除代码
2.action字段功能完善
kingadmin.py中放置action字段,包含有自定义方法
admin_base.py中需要去设置action默认数据
(1)设置form表单布局
form表单
(2)设置复选框完成全选功能
HTML代码
CheckAll方法js完成全选
(3)提交表单前先生成隐藏表单去获取数据集
Raw_input_action方法生成一个人input标签
(4)传递到后端进行处理
在table_obj_list方法添加上post方法即可
3.处理action中的默认行为delete批量删除
(1)提交的url不是上面的table_obj_delete,而是本页面和change_status一起作为action传递入当前url
delete_selected_objs的action方法
(2)获取delete_selected_objs在table_obj_list方法中返回
table_obj_list中对于post的处理
若是执行完action方法后没有返回值则是正常执行,如果有返回值,则是代表我们接下来是执行删除操作。需要返回
(3)我们还是调用的上面的table_obj_delete.html页面,但是其中的模板标签函数,是针对一个数据对象,而现在是一个数据集,我们需要再次处理
简单改变模板函数get_del_obj,将原来单个对象也改写为可迭代
(4)我们提交数据,也不再是table_obj_delete方法,而是table_obj_list方法,所以我们需要传递一个数据代表要删除的数据id集合,同时一个一个标识
在显示的table_obj_delete.html页面加入隐藏标签,收集所有id集合
get_del_objs_id模板函数收集所有的数据对象的id,json序列化返回给前端
(5)views页面根据post传递过来的隐藏标签的name,判断是不是执行删除数据操作
获取前端input表单名delete_ids,判断是否有数据,来决定是否删除
4.实现面包屑导航
add页面导航
list页面导航
change页面导航
get_nva_active模板函数获取对象的中文名
delete页面导航
get_nav_del模板函数组合对象名
5.左侧菜单状态
index页面在生成url时,对其进行判断。要分辨动态和绝对
Day6:学员报名流程开发
新增3张表:学员注册表,合同表(和班级关联),缴费记录表
一:销售为想报名的学员提供链接
Student_encroll学员注册链接获取
二:学员获取链接,进行填写信息,查阅合同,同意并上传证件信息
enrollment学员在线报名
erollment.html报名页面,含有Dropzone使用
enrollment_fileupload处理Dropzone文件传输
三:销售审核学员注册信息,审核通过,为其生成账号(密码需要使用Django模块加密),发送邮件
from django.contrib.auth.hashers import make_password #用于生成密码
contract_audit合同审核后生成账号,发送信息
Django自带邮件发送模块
(1)settings中配置
(2)导入模块发送邮件
day7:实现讲师和学员作业发布上传功能(其中由于多使用table浏览数据,可以自定义一个类似于form的基类,去统一实现table显示)
一:讲师功能
(1)可以看出上面多是table显示信息,下面自定义table_form类似于forms
BaseForm实现通过表数据显示table
(2)使用方法
from Teacher.table_form import BaseForm
class ClassListForm(BaseForm):
display_list = ["self","branch","class_type","start_date","graduate_date"] #self代表直接显示本条数据__str__
field_tag = {"self":{"a":{"href":"127.0.0.1:8000"},},"study_record":{"a":{"href":"/teacher/classlist/{id}/class_list.html"}},"student":{"a":{"href":"/teacher/classlist/{id}/student_list.html"}}} #在前面的标签会显示在内层,在显示的数据外面加上标签
attrs = {"class":"table table-hover"} #为table设置属性
extra_field = [{"student":{'verbose_name':"学员数量","model_attr":"student_set","function":"count"}},{"study_record":{"verbose_name":"上课记录","value":"上课记录"}}]
#额外自定义字段,若是有值value,会直接输出,否则会去当前实例集self.querysets的每一个实例中去获取相关的数据,使用函数去执行。字符串是调用自己的内置方法,function是调用自定义方法,同时可以使用"args"传递元组,"kwargs":传递字典作为参数
def __init__(self,model,querysets):
super(ClassListForm, self).__init__(model,querysets)
StudentForm
CourseForm
(3)在views中调用各个tableform
所有显示table的函数
(4)前端调用{{ forms|safe }},form是定义的tableform变量,实现简单显示页面
class_list.html
course_list.html
student_list.html
(5)添加记录
使用form类,生成控件
views调用classRec_add,进行显示和添加数据
前端显示course_add.html
二:学员功能,实现课程显示,作业提交
(一)根据邮件中的账号密码登录
(二)实现查看班级,查看课程记录,提交作业
(1)由于这里也是table多使用,可以继续使用tableform
from Teacher.table_form import BaseForm
class ClassListForm(BaseForm):
display_list = ["self","class_type","start_date","graduate_date",] #,"couser","semester"
field_tag = {"self":{"a":{"href":"127.0.0.1:8000"},},'score':{"a":{"href":"127.0.0.1:8080"},},'mng_homework':{"a":{"href":"/student/course.html"}}} #在前面的标签会显示在内层
attrs = {"class":"table table-hover"}
extra_field = [{"score":{"verbose_name":"成绩","value":"成绩排名"}},{"mng_homework":{'verbose_name':"作业管理","value":"作业管理"}},]
class ClassRecordForm(BaseForm):
display_list = ["self","title","teacher","content","has_homework","homework"] #,"couser","semester"
field_tag = {"self":{"a":{"href":"127.0.0.1:8000"},},'fin_homework':{"a":{"href":"/student/homework/{id}.html"}}} #在前面的标签会显示在内层
attrs = {"class":"table table-hover"}
extra_field = [{"date":{"verbose_name":"日期","model_attr":"date","function":"strftime","args":("%Y-%m-%d %H:%M:%S",)}},{"fin_homework":{'verbose_name':"我的作业","value":"提交作业"}},]
#额外自定义字段,若是有值value,会直接输出,否则会去当前实例集self.querysets的每一个实例中去获取相关的数据,使用函数去执行。字符串是调用自己的内置方法,function是调用自定义方法
def __init__(self,model,querysets):
super(ClassRecordForm, self).__init__(model,querysets)
(2)view中调用,显示班级和课程,前端也是{{forms|safe}}
显示班级和课程
(3)使用forms表单显示数据,使用Dropzone添加作业
CourseRecordForm
homework作业显示和添加
(4)前端代码,使用Dropzone处理数据,以及ajax删除数据
homework.html
(5)后台处理数据删除
delete_files根据ajax上传数据删除文件
总结:学会偷懒,化繁为简,学会总结业务,再去动态处理,而不是一直对数据库的增删改查,和重复一个业务逻辑
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)