crm笔记

大目标:crm系统。
--权限组件
--stark组件
--crm业务

	步骤:
	第一部分权限组件:
		1.创建django project,luffy-permission
		2.两个app
			--rbac,权限组件
			--web,销售管理系统
		3.app: rbac
			-将权限相关的表编写到此app的models.py中
	4.app:web
	 	-将销售管理系统表写到此app的models.py中
		-销售系统的业务代码
		
	5.两个app的整合
		客户管理
			客户列表:/customer/list/
			添加客户:/customer/add/
			删除客户:/customer/del/(?P<cid>\d+)/
			修改客户:/customer/edit/(?P<cid>\d+)/
			批量导入:/customer/import/
			下载模板:/customer/tpl/
		账单管理
			账单列表:/payment/list/
			添加账单:/payment/add/
			删除账单:/payment/del/(?P<pid>\d+)/
			修改账单:/payment/edit/(<?P<pid>\d+/

		那么接下来,我们就在权限组件中录入相关信息:
			录入权限
			创建用户
			创建角色
			用户分配角色
			角色分配权限
	6.权限控制设计思路--初始化
		--减少数据库的压力,在中间件request.session中检验权限
			1.登录页面是否有权限访问。 所有人都可访问
			2.post请求,用户登录检验是否合法,不合法返回继续登录
			3.登录成功后,获取当前用户的所有权限并放入session
			4.中间件中控制:当在向服务器发起请求url时候,后端编写中间件对用户当前访问的url进行权限的判断(是否在session中)
	7.功能完善,将权限相关的代码当如rbac组件中
		--权限初始化代码 归类
			1.登录代码和权限初始化拆分
			2.settings.PERMISSION_SESSION_KEY 在设置中配置
	总结:6,7权限的控制

	8.动态菜单
		--一级菜单 如何实现动态显示一级菜单?
			a.变结构修改+录入菜单数据
			b.获取菜单信息并保存到session
			c.模板中显示信息  引入:inclusion_tag渲染模板

		--二级菜单
			a.表结构
				fa-free-code-camp
				fa-money

				{
					1:{
						title:'用户信息',
						icon:'x1',
						chirldren:[
							{title:'个人信息',url:'/userinfo/'},
						]
					},
					2:{
						title:'客户信息',
						icon:'x1',
						chirldren:[
							{title:'客户列表',:'/userinfo/'},
						]
					},				
				}
			b.表结构:
				class Menu(models.Model):
				    """
				    菜单表
				    """
				    title =models.CharField(verbose_name='一级菜单名称',max_length=32)
				    icon = models.CharField(verbose_name='图标',max_length=32,blank=True,null=True)


				class Permission(models.Model):
				    """
				    权限表
				    """
				    title = models.CharField(verbose_name='标题',max_length=32)
				    url = models.CharField(verbose_name='含正则的url',max_length=128)

				    menu= models.ForeignKey(verbose_name='所属菜单',to='Menu',on_delete=models.CASCADE,blank=True,null=True,help_text='null表示不是菜单,非null表示二级菜单')
				    def __str__(self):
        				return self.title				
        	c.页面显示二级菜单  默认设置一级菜单隐藏 class = hide,并才css中设置具体的样式

      9.点击非菜单的权限时,默认选中或默认展开
	      	当点击某个不能成为菜单的权限时,指定一个可以成为菜单的权限,也让其默认选中以及展开
	      	在Permission表中加自关联pid,要加一个related_name='parents'
      	a.数据库涉及
      	b.思路
      		-登录,做权限和菜单的初始化
      			--获取菜单信息
	      			{
						1:{
							title:'用户信息',
							icon:'x1',
							chirldren:[
								{id:1,title:'个人信息',url:'/userinfo/'},
							]
						},
						2:{
							title:'客户信息',
							icon:'x1',
							chirldren:[
								{id:7,title:'客户列表',:'/userinfo/'},
							]
						},				
					}
      			--获取权限信息
      					{
      						{id:1,url:'/customer/list',pid=null}, 客户列表,可做菜单
      						{id:2,url:'/customer/add',pid=1}, #添加菜单不可做菜单,默认选pid=1的客户列表做菜单
      						{id:3,url:'/customer/del/(?P<cid>\d+)',pid=7},
      					}
      		-再次登录时,到中间件中做校验(根据权限信息)
	      		-从request.session中获取权限信息,id或pid 
	      		-在通过request,将pid或者id传到inclusion_tag
	      			(request.current_selected_url=item['pid'] or item['id'])

      		-模板中使用动态菜单--inclusion_tag动态生成菜单(根据菜单信息)
      			从request.session中获取菜单信息
      10.路径导航  
      			breadcrumb
      			--首页/账单列表/添加账单
      11.权限的粒度控制到按钮级别:
	      	--修改数据库--加url别名name(customer_list)--->>permission_dict 以URL别名做key值
	      	--过滤器filter可以在if后面当条件,而tag和inclusion_tag不能(自己定义一个过滤器,最多2个参数)
	      		 {% if request|has_permission:"customer_add"%}
	                <a class="btn btn-default" href="/customer/add/">
	                    <i class="fa fa-plus-square" aria-hidden="true"></i> 添加客户
	                </a>
	            {% endif %}

	  总结:
	  	- 权限控制
	  	- 动态菜单
	  	- 权限的分配
	  	问题:以前你是如何进行权限分配的?给某个用户分配一个角色?某个人分配权限
	  	答案:django admin进行录入

	  12.权限分配  先把权限校验的中间件去掉了,左边栏和导航栏也去掉了
		  	a.角色管理 Role
		  	--forms.ModelForm和forms.Form 
		  		from django import forms
	  		class RoleModelForm(forms.ModelForm):
			    """
			    角色组件
			    """
			    class Meta:
			        model=models.Role
			        fields=['title',]

			        widgets={
			            'title':widgets.TextInput(attrs={'class':'form-control'})
			        }
			        labels = {
			            "title": "角色名称"
			        }
			        error_messages = {
			            'title':{'required':"角色名不能为空",},
			        }

	  		(RoleModelForm(instance=obj,data=request.POST),编辑的需要把编辑的obj传入组件)

	  	--include路由分发时的名称空间,和rbac.urls里的name
	  	--django模板的查找顺序,以及add/edit模板复用,del模板复用

	  b.用户管理 UserInfo
	  	--知识点:
	  		1.forms.ModelForm 
		  		字段的新增,
		  		钩子方法,
		  		super,重写init方法,统一给所有字段添加属性
		  		中文显示错误信息:配置中LANGUAGE_CODE = 'zh-hans'
	  		2.根绝namespace和name反向生成url,在模板中和py文件中2中方式
	  		3.模板的查找顺序
	  c.菜单和权限管理 Menu/Permission
	  		---ModelForm 操作一张表
	  		1.panel 公告框
	  		2.保留原有搜索条件 自定义simple_tag:memory_url (类似原生url)
	  		3.模板中整型转成字符串|safe
	  		4.ModelForm中 forms.RadioSelect 选择框
				from django.utils.safestring import mark_safe
				class MenuModelForm(forms.ModelForm):
				    class Meta:
				        model = models.Menu
				        fields=['title','icon']
				        widgets = {
				            'title':forms.TextInput(attrs={'class':'form-control'}),
				            'icon':forms.RadioSelect(
				                choices=[
				                    ['fa-address-book-o',mark_safe('<i class="fa fa-address-book-o" aria-hidden="true"></i>')],
				                    ['fa-envelope-open',mark_safe('<i class="fa fa-envelope-open" aria-hidden="true"></i>')],
				                    ['fa-envelope-open-o',mark_safe('<i class="fa fa-envelope-open-o" aria-hidden="true"></i>')],
				                ],
				                attrs={'class':'clearfix'}

				            )
				        }
			5.ModelForm中 下拉框设置默认值
				menu_object = models.Menu.objects.filter(pk=menu_id).first() #为了能设置默认值。需要一级菜单的id
				form = SecondMenuModelForm(initial={'menu':menu_object})
			6.ModelForm中 save之前 在数据库中设置二级菜单 form.instance.pid = seconde_menu_obj  #在数据库里默认添加二级菜单
			7.BootstropModelForm 自定义样式定制


	  d.权限的批量操作
	  		--formset
	  			什么是formset?
	  				答:Form组件或ModelForm用于做一个表单验证(数据库的一张表里对应的一条数据)
	  				formset:指的是可以用与多个表单的验证组件
	  				应用场景?
	  					--批量操作

	  		--自动发现所有URL	  (from django.urls import URLResolver,URLPattern)
	  			--问题:找到项目中的所有url
	  				{
	  				'rbac:menu_list:{name:'rbac:menu_list',url:'rbac/menu/list'}
	  				}
					    
			--批量的权限操作
				思路:
				1.获取项目中所有的权限 set1
				2.去数据库中获取已经录入的所有权限 set2

				情况1::自动发现的 >数据库中的 -->实现批量添加 ps:通过name进行比对(model中设置唯一)
				set1 - set2 ==>添加  formset 
				情况2:数据中的 > 自动发现 -->实现批量删除
				set2 - set1 ==>删除
				情况3: 自动发现的 > 数据库有的 --实现批量更新
				set3 = set1 & set2 ==>更新 formset

	  e.权限分配	  
	  	--展示用户/角色/权限信息
	  		
	  	--选择用户/角色时,页面上的默认选项

	  	--角色和权限分配【保存】	
	  		列表==>赋值给字典--引用同一块内存地址	

 rbac使用文档README

第二部分stark组件:
	介绍:stark组件,是一个帮助开发者快速实现数据库表的增删改查
	目标:10s 完成一张表的增删改查

	前戏:
		1.django项目启动时,自定义执行某个文件
			在django项目启动前,且在读取路由加载前,执行某个py文件
			在 任意的 app的apps.py中的Config类,定义ready方法,调用autodiscover_modules
			from django.apps import AppConfig
			from django.utils.module_loading import autodiscover_modules

			class App01Config(AppConfig):
			    name = 'app01'

			    def ready(self):
			        autodiscover_modules('xxx')
			django在启动前,就会去已经注册的app的目录下找xxx.py并自动执行

			如果执行两次,是因为django内部自动重启导致,2个线程,一个时启动项目,另一个看代码更新状态
				python manage.py runserver 127.0.0.1:8001 --noreload #只执行一次
			提示:
				如果xxx.py执行的代码,向其他地方放入了一些值,之后的路由加载时,可以去那里读取

		2.单例模式
			单:一个
			例:实例,对象
			通过利用python模块导入的特性,如果已经导入的模块在被重新导入时,python不会在重新解释一遍,而是选择从内存中读取原来导入的值
			提示:
				如果以后存在一个单例模式的对象,可以先在此对象中放入一个值,
				然后在其他的文件中导入该对象,通过对象再次,将值获取到

		3.django路由分发的本质include
		    re_path(r'^rbac/', include(([
		    			    re_path(r'^role/list/$', role.role_list,name='role_list'), # rbac:role_list
							re_path(r'^role/add/$', role.role_add,name='role_add'),
		    ], 'rbac'),namespace='rbac')),

			--- urlconf_module, app_name, namespace

	开始!
	1.创建一个project
	2.创建基础业务表
	app01/models.py
		用户表
		部门表
	app02/models.py
		主机表
	3.对 以上三张表做增删改查
		a.为每张表创建4个url 
		b.为每张表创建4个视图函数
		app01/models.py
            Depart
                /app01/depart/list/
                /app01/depart/add/
                /app01/depart/edit/(\d+)/
                /app01/depart/del/(\d+)/				

			UserInfo
                /app01/userinfo/list/
                /app01/userinfo/add/
                /app01/userinfo/edit/(\d+)/
                /app01/userinfo/del/(\d+)/		
		app02/models.py
            Host
                /app02/host/list/
                /app02/host/add/
                /app02/host/edit/(\d+)/
                /app02/host/del/(\d+)/

        为app中的每个model类 自动创建url以及视图函数

         - 动态生成url
         - 视图提取到基类
         - URL&分发扩展 &后缀
         - URL设置别名name
         - URL的别名进行重新的生成 优化

         c.定制html页面显示的列
         	- 基本完成列表页面的定制
         	- 未定义list_display字段的页面,默认显示对象
         	- 为页面显示的列预留一个钩子函数 扩展
         	- 页面自定义显示的列的函数
         d.应用模板样式(layout.html/bootstarp)


         e.分页功能
         f.添加按钮
         	- 如何显示添加按钮
         	- 添加按钮的url
         	- 添加界面进行添加数据(保留原搜索条件)

         g.编辑
         	- 编辑按钮
         	- 页面操作
         h.删除


    4.其他功能
    	- 排序
    	- 模糊搜索
    		- 实现思路:
    			在页面上设置form表单,已get形式提交搜索条件到后台,后台获取数据,
    			进行数据筛选,根据自定义的列表search_list进行查找(多列可以按照或进行查询(crm中Q语法))

    	- 动态搜索
    	- 批量操作
    		- 添加checkbox列
    		- 生成批量操作的按钮
    	- 组合搜索
    		- 什么是组合搜索?
    		- 如何实现?
    			- 实现思路:根据字段找到与其关联的数据:choice、foreginkey、manytomany
    			  - 1.配置 search_group = ['gender','depart'] #想要分2组
    			  - 2.根据配置获取到数据
    			  - 3.跟据配置获取到数据(含条件)
    			  - 4.在页面上显示组合搜索的按钮(在后台生成html代码)
    			  		将queryset_or_tuple进行封装
    			  -5.为组合搜索按钮生成URL
    			  -6.多选搜索

   	总结: - 页面:了,列表、添加、编辑、删除
   		  -  模糊搜索、批量操作、组合搜索


第三部分:crm业务开发
	1.项目背景介绍:
		以教育机构为背景的crm项目,系统主要为销售部、运营部、教质部、提供平台,对他们的工作进行量化
		销售部:
			- 公户,公共用户
			- 私户,我的用户。 <=150人 +跟进记录+入班申请(财务审核)
		运营部:
			- 录入客户信息(公户)
		教质部:
			- 考勤
			- 学院访谈
			- 积分管理
			- 转班申请
	2.项目开发
		2.1 概况
			- 基础业务处理
				- 校区管理
				- 部门管理
				- 用户管理
				- 课程管理
				- 开班管理
			- 客户管理
				- 公户
				- 私户
			- 学员管理
				- 考勤
				- 谈话记录
				- 积分
			- rbac组件
		2.2
			- 2.2.1 创建项目
			- 2.2.2 校区管理
			- 2.2.3 部门管理
			- 2.2.4 用户管理
				- 页面基本操作 添加 编辑 删除
				- 添加页面需要新增一个确认字段 $编辑页面删除密码字段
		 	    - 重置密码	
		 		- 新加一条路由 (用预留的钩子extra_url)
		 		- 加视图、前端界面、保留原搜索条件(反向生成url)
		 		- 页面功能的增加(模糊搜索、组合搜索)

		 	- 2.2.5 客户管理+代码的拆分到views中 
		 	- 2.2.6 班级管理
		 			- 班级管理基本操作(定制display_course显示列)
		 			- 基于limit_choice_to 对于关联的Fk,M2M进行筛选
		 			limit_choices_to={'depart__title__in':['Linux教学部','Python教学部']}
		 			- 班级管理时间插件的应用(stark组件新增DateTimePickerInput插件、
		 			【from stark.forms.DateTimePickerInput import DateTimePickerInput】)
		 	- 2.2.7 客户管理
		 		- 公户
		 			- 公户基本管理:公户列表、录入客户
		 			- 查看跟进记录
		 			- 批量申请到私户:个数限制、数据库中事务加锁、添加当前登录人(即为我的私户)
		 			- 用户登录 后将user_id存到session中,后续取的时候从session中获取
		 		- 私户
		 		    - 私户基本管理 添加时客户顾问默认是登录人自己,在数据库中添加(预留的钩子save)
		 		    - 私户剔到公户
		 		    - 跟进记录管理 -- 根据strark组件生成url
		 		    	- 查看 
		 		    	- 添加 
		 		    	- 编辑 
		 		    	- 删除 
		 		- 缴费&报名
		 			- 业务分析
			 			- 学员缴费
			 			- 课程顾问:提交缴费申请
			 			- 财务:审核(状态更新、入班学习)
			 		- 代码实现
			 			- 表结构设计 
			 			- 查看缴费列表
			 			- 添加缴费记录
			 			- 缴费审批

			- 2.2.8 学员管理
					- 学生管理
					- 积分管理
					- 考勤管理
						- 上课记录
						- 考勤记录
			- 2.2.9 权限应用
					- 基本权限校验
					- 粒度控制到按钮
posted @ 2020-03-18 15:18  hanfe1  阅读(240)  评论(0编辑  收藏  举报