Django项目:CRM(客户关系管理系统)--85--75PerfectCRM实现CRM扩展权限
1 # sales_urls.py 2 # ————————47PerfectCRM实现CRM客户报名流程———————— 3 from django.conf.urls import url 4 from bpm.sales import sales_views 5 6 urlpatterns = [ 7 8 # ————————75PerfectCRM实现CRM扩展权限———————— 9 url( r'^sales_customer/$', sales_views.sales_customer, name='sales_customer' ), # 销售自己的客户库 10 # ————————75PerfectCRM实现CRM扩展权限———————— 11 12 url(r'^customer/(\d+)/enrollment/$', sales_views.enrollment, name="enrollment"),#客户招生#报名流程一 下一步 13 14 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 15 # ————————48PerfectCRM实现CRM客户报名流程学生合同———————— 16 # url(r'^customer/registration/(\d+)/$', sales_views.stu_registration, name="stu_registration"), # 报名流程二 学员签同合 17 # ————————48PerfectCRM实现CRM客户报名流程学生合同———————— 18 url(r'^customer/registration/(\d+)/(\w+)/$', sales_views.stu_registration, name="stu_registration"), # 报名流程二 学员签同合 19 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 20 21 # ————————52PerfectCRM实现CRM客户报名流程学生合同审核———————— 22 url(r'^contract_prompt/$', sales_views.contract_prompt, name="contract_prompt"), # 报名流程二 提示学员 23 url(r'^not_audit/$', sales_views.not_audit, name="not_audit"), # 报名流程二 未审核 查询 24 url(r'^contract_review/(\d+)/$', sales_views.contract_review, name="contract_review"), # 报名流程三 审核 25 url(r'^enrollment_rejection/(\d+)/$', sales_views.enrollment_rejection, name="enrollment_rejection"), # 报名流程三 驳回 26 # ————————52PerfectCRM实现CRM客户报名流程学生合同审核———————— 27 28 ] 29 # ————————47PerfectCRM实现CRM客户报名流程————————
1 # sales_views.py 2 # ————————47PerfectCRM实现CRM客户报名流程———————— 3 from django.db import IntegrityError # 主动捕捉错误信息 4 from django.shortcuts import render # 页面返回 5 from crm import models # 数据库 6 from bpm.bpm_auxiliary import bpm_forms # 自定制 forms 7 from django.contrib.auth.decorators import login_required # 登陆后页面才能访问 8 9 # ————————47PerfectCRM实现CRM客户报名流程———————— 10 from django.core.mail import send_mail 11 # send_mail的参数分别是 邮件标题,邮件内容,发件箱(settings.py中设置过的那个),收件箱列表(可以发送给多个人),失败静默(若发送失败,报错提示我们) 12 import random 13 import datetime # 获取时间#登陆过期 14 # ————————74PerfectCRM实现CRM权限和权限组限制访问URL———————— 15 from permissions.permission import check_permission #权限控制 16 # ————————74PerfectCRM实现CRM权限和权限组限制访问URL———————— 17 18 19 # ————————75PerfectCRM实现CRM扩展权限———————— 20 #销售自己的客户库 21 def sales_customer(request): 22 user_id=request.user.id #当前登陆的ID 23 return redirect( '/king_admin/crm/customer/?consultant=%s' %(user_id) ) # 跳转到enrollment_rejection 24 # ————————75PerfectCRM实现CRM扩展权限———————— 25 26 27 # 发送邮件的功能 #验证码#密码 28 class stmp(): 29 def __init__(self): 30 self.emaillist = [] # 发送给谁 31 self.code = None # 验证码#密码 32 33 def stmps(self, request, email, msg_mail): # 传参数#页面,session #邮箱,发送给谁 #内容 34 self.emaillist.append(email) # 将邮箱地址添加到调用Django发送邮件功能 35 # ——————生成验证码—————— 36 _letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z 37 _upper_cases = _letter_cases.upper() # 大写字母 38 _numbers = ''.join(map(str, range(3, 10))) # 数字 39 chars = ''.join((_letter_cases, _upper_cases, _numbers)) # 变成一条字符串 40 list = random.sample(chars, 4) # 从一条字符串随机选4个字符变成列表 41 self.code = ''.join(list) # 列表变字符串 42 # ——————生成验证码—————— 43 # ——————调用Django发送邮件—————— 44 title = 'PerfectCRM项目自动邮件:%s' % self.code # 邮件标题#防止一样的内容被邮箱屏蔽 45 send_mail(title, # 邮件标题 46 msg_mail, # 验证码内容 47 'perfectcrm@sina.cn', # 发送的邮箱 #根据情况重新配置 48 self.emaillist, # 接受的邮箱 49 fail_silently=False, # 静默,抛出异常 50 ) 51 print('发送邮件成功!没收到要换标题!检查发送邮箱的配置!') 52 # ——————调用Django发送邮件—————— 53 # ————————47PerfectCRM实现CRM客户报名流程———————— 54 # ————————47PerfectCRM实现CRM客户报名流程———————— 55 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 56 import random # 随机 57 import string # 字母 数字 58 from django.core.cache import cache # 缓存 59 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 60 61 # 报名填写 销售 62 @login_required # 登陆后页面才能访问 63 @check_permission #权限控制 64 def enrollment(request, customer_id): 65 msgs = {} # 错误信息 66 customer_obj = models.Customer.objects.get(id=customer_id) # 取到客户信息记录 #返回到页面#报名人 67 consultant_obj = models.UserProfile.objects.get(id=request.user.id) # 报名课程顾问 68 69 stmp_mail = {} # 邮件发送成功 70 stmpemail = stmp() # 实例化发送邮件的功能 71 email = request.POST.get('email') # 让页面POST提交的值,在页面GET后仍然存在显示 72 if request.method == "POST": 73 enroll_form = bpm_forms.EnrollmentForm(request.POST) # 获取数据 74 if enroll_form.is_valid(): # 表单验证 75 76 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 77 # msg = "http://127.0.0.1:8000/bpm/customer/registration/{enroll_obj_id}/" 78 msg = "http://127.0.0.1:8000/bpm/customer/registration/{enroll_obj_id}/{random_str}/ " 79 random_str = ''.join(random.sample(string.ascii_lowercase + string.digits, 8)) # 生成8位随机字符串 #URL使用 80 url_str = '''customer/registration/{enroll_obj_id}/{random_str}/''' # 报名链接 81 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 82 83 try: 84 enroll_form.cleaned_data['customer'] = customer_obj # 添加学员对象 记录 #报名人 85 enroll_form.cleaned_data['consultant'] = consultant_obj # 报名课程顾问 86 enroll_obj = models.Enrollment.objects.create(**enroll_form.cleaned_data) # 创建记录 87 88 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 89 # msgs['msg']=msg.format(enroll_obj_id=enroll_obj.id)#报名记录对应的id,随机字符串,报名链接 90 sort_url = enroll_obj.id # 获取报名表对应的ID 91 cache.set(enroll_obj.id, random_str, 61000) # 加入过期时间 #URL使用 # cache缓存 92 msgs['msg'] = msg.format(enroll_obj_id=enroll_obj.id, random_str=random_str) # 报名记录对应的id,随机字符串,报名链接 93 url_str = url_str.format(enroll_obj_id=enroll_obj.id, random_str=random_str) # 报名链接 94 print(url_str) 95 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 96 except IntegrityError as e: 97 # 取到这条记录 98 enroll_obj = models.Enrollment.objects.get(customer_id=customer_obj.id, 99 enrolled_class_id=enroll_form.cleaned_data[ 100 'enrolled_class'].id) 101 102 # ————————52PerfectCRM实现CRM客户报名流程学生合同审核———————— 103 if enroll_obj.contract_agreed:#学员已经同意合同,提交了身份证 104 #return redirect('/crm/contract_review/%s/'%enroll_obj.id)#跳转到审核页面 105 return render(request,'bpm_sales/contract_prompt.html',locals())#跳转提示页面 106 # ————————52PerfectCRM实现CRM客户报名流程学生合同审核———————— 107 108 enroll_form.add_error('__all__', '记录已经存在,不能重复创建!') 109 110 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 111 # msgs['msg']=msg.format(enroll_obj_id=enroll_obj.id)#报名记录对应的id 112 cache.set(enroll_obj.id, random_str, 61000) # 加入过期时间 #URL使用 # cache缓存 113 msgs['msg'] = msg.format(enroll_obj_id=enroll_obj.id, random_str=random_str) # 报名记录对应的id 114 url_str = url_str.format(enroll_obj_id=enroll_obj.id, random_str=random_str) # 报名链接 115 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 116 117 if email: 118 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 119 # msg_mail = "http://127.0.0.1:8000/bpm/customer/registration/%s" %enroll_obj.id 120 msg_mail = "http://127.0.0.1:8000/bpm/customer/registration/%s/%s" %(enroll_obj.id,random_str) 121 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 122 stmpemail.stmps(request, email, msg_mail) # 发送邮件 123 stmp_mail['ok'] = "邮件已发送成功!" 124 125 else: 126 enroll_form = bpm_forms.EnrollmentForm() # modelform表单 127 return render(request, 'bpm_sales/enrollment.html', locals()) 128 # ————————47PerfectCRM实现CRM客户报名流程———————— 129 130 131 # ————————48PerfectCRM实现CRM客户报名流程学生合同———————— 132 #学员合同签定 133 134 # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片———————— 135 import os 136 from PerfectCRM import settings 137 import json 138 # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片———————— 139 140 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 141 from django.shortcuts import HttpResponse #页面返回 142 # def stu_registration(request,enroll_id): 143 def stu_registration(request,enroll_id,random_str): 144 # enroll_obj=models.Enrollment.objects.get(id=enroll_id)#获取报名记录 145 if cache.get(enroll_id) == random_str: # 判断链接失效了没有 146 enroll_obj = models.Enrollment.objects.get(id=enroll_id) # 报名记录 147 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 148 149 # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片———————— 150 enrolled_path='%s/%s/'%(settings.ENROLLED_DATA,enroll_id)#证件上传路径 151 img_file_len=0 #文件 152 if os.path.exists(enrolled_path):#判断目录是否存在 153 img_file_list=os.listdir(enrolled_path)#取目录 下的文件 154 img_file_len=len(img_file_list) 155 # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片———————— 156 157 # ————————49PerfectCRM实现CRM客户报名流程学生合同表单验证———————— 158 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 159 if request.method == "POST": 160 161 # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片———————— 162 ret=False 163 data=request.POST.get('data') 164 if data:#如果有删除动作 165 del_img_path="%s/%s/%s"%(settings.ENROLLED_DATA,enroll_id,data)#路径 166 print(del_img_path,'=-=-=-=-=-=') 167 os.remove(del_img_path) 168 ret=True 169 return HttpResponse(json.dumps(ret)) 170 if request.is_ajax():#ajax上传图片 #异步提交 171 print('ajax上传图片 #异步提交中。。。 ',request.FILES) 172 enroll_data_dir="%s/%s"%(settings.ENROLLED_DATA,enroll_id)#路径 #重要信息不能放在静态文件中 173 if not os.path.exists(enroll_data_dir):#如果不存目录 174 os.makedirs(enroll_data_dir,exist_ok=True)#创建目录 175 for k,file_obj in request.FILES.items(): #循环字典 #上传的文件 176 with open("%s/%s"%(enroll_data_dir,file_obj.name),'wb') as f: #打开一个文件#路径#获取文件名 177 for chunk in file_obj.chunks():#循环写入文件 # chunks块 178 f.write(chunk) #保存文件 179 return HttpResponse('上传完成!') 180 # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片———————— 181 182 customer_form = bpm_forms.CustomerForm(request.POST, instance=enroll_obj.customer) # 生成表单验证 183 if customer_form.is_valid(): # 表单验证通过 184 customer_form.save() # 保存 185 enroll_obj.contract_agreed = True # 同意协议 186 enroll_obj.save() # 保存 187 status = 1 # 修改报名状态 # 1 已经报名 188 return render(request, 'bpm_sales/stu_registration.html', locals()) 189 190 else: 191 if enroll_obj.contract_agreed == True: # 如果协议已经签订 192 status = 1 # 修改报名状态 # 1 已经报名 193 else: 194 status = 0 195 customer_form = bpm_forms.CustomerForm(instance=enroll_obj.customer) # 生成表单 196 # customer_form = bpm_forms.CustomerForm(instance=enroll_obj.customer) # 生成表单 197 # ————————49PerfectCRM实现CRM客户报名流程学生合同表单验证———————— 198 199 return render(request,'bpm_sales/stu_registration.html',locals()) 200 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 201 # ————————48PerfectCRM实现CRM客户报名流程学生合同———————— 202 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 203 else: 204 return HttpResponse('链接失效,非法链接,请自重!') 205 # ————————50PerfectCRM实现CRM客户报名流程学生合同URL随机码———————— 206 207 208 # ————————52PerfectCRM实现CRM客户报名流程学生合同审核———————— 209 from django.shortcuts import redirect 210 #查询流程提示页面 211 def contract_prompt(request,enroll_id): 212 enroll_obj=models.Enrollment.objects.get(id=enroll_id)#取对象 213 enroll_form= bpm_forms.EnrollmentForm(instance=enroll_obj)#报名表对象 214 customers_form= bpm_forms.CustomerForm(instance=enroll_obj.customer)#学员的信息 215 return render(request,'bpm_sales/contract_prompt.html',locals()) 216 217 # ————————68PerfectCRM实现CRM业务流程(bpm)报名缴费分页———————— 218 from bpm.bpm_auxiliary.pagination import Page #分页 219 # ————————68PerfectCRM实现CRM业务流程(bpm)报名缴费分页———————— 220 # #待审核 221 @login_required # 登陆后页面才能访问 222 @check_permission #权限控制 223 def not_audit(request): 224 # ————————68PerfectCRM实现CRM业务流程(bpm)报名缴费分页———————— 225 # sign=models.Enrollment.objects.all()#所有的报名表 226 # print(sign,'sign----->') 227 sign=models.Enrollment.objects.filter(contract_agreed=True,contract_approved=False).all()#所有的报名表 228 229 page = Page(request.GET.get('p', 1), len(sign)) #当前页数 默认为1 #总数量 230 sign = sign[page.start:page.end] # 切片取当前页的数据 231 page_str = page.page_str('/bpm/not_audit/') #总页数 传入url 232 # ————————68PerfectCRM实现CRM业务流程(bpm)报名缴费分页———————— 233 return render(request, 'bpm_sales/not_audit.html', locals())# 234 235 #审核合同 236 @login_required # 登陆后页面才能访问 237 @check_permission #权限控制 238 def contract_review(request,enroll_id): 239 enroll_obj=models.Enrollment.objects.get(id=enroll_id)#取对象 240 contract_review = request.user.name #当前登陆人 #合同审核人 241 #payment_form=forms.PaymentForm()#生成表单 242 enroll_form= bpm_forms.EnrollmentForm(instance=enroll_obj)#报名表对象 243 customer_form= bpm_forms.CustomerForm(instance=enroll_obj.customer)#学员的信息 244 enrolled_path='%s/%s/'%(settings.ENROLLED_DATA,enroll_id)#证件上传路径 245 if os.path.exists(enrolled_path):#判断目录是否存在 246 file_list=os.listdir(enrolled_path)#取目录 下的文件 247 imgs_one=file_list[0] #图片1 248 imgs_two=file_list[1] #图片2 249 if request.method=="POST": 250 enroll_obj.contract_approved = True # 审核通过 251 enroll_obj.save() #保存 252 enroll = models.Enrollment.objects.filter(id=enroll_id).update(contract_review=contract_review)#合同审核人 253 print('审核通过。。。') 254 return redirect('/bpm/not_audit/')#跳转到待审核 255 return render(request, 'bpm_sales/contract_review.html', locals())# 256 #驳回合同 257 def enrollment_rejection(request,enroll_id): 258 enroll_obj=models.Enrollment.objects.get(id=enroll_id)#报名表的对象 259 enroll_obj.contract_agreed=False#修改学员已经同意核同 260 enroll_obj.save() #保存 261 return redirect('/bpm/customer/%s/enrollment/'%enroll_obj.customer.id)#跳转到enrollment_rejection 262 # ————————52PerfectCRM实现CRM客户报名流程学生合同审核————————
1 #models.py 2 3 # ————————01PerfectCRM基本配置ADMIN———————— 4 5 from django.db import models 6 # Create your models here. 7 8 """ 9 #运行 Terminal 10 # 生成 数据表 11 # python manage.py makemigrations 12 # 数据表 迁移 13 # python manage.py migrate 14 """ 15 16 """01校区表""" 17 class Branch(models.Model): 18 name = models.CharField(max_length=128,unique=True) #校区名#CharField作用是保存文本,定长的变量类型 19 addr = models.CharField(max_length=128) #地址 20 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 21 return self.name #返回 #校区名 22 class Meta: #通过一个内嵌类 "class Meta" 给你的 model 定义元数据 23 verbose_name_plural = "01校区表" #verbose_name_plural给你的模型类起一个更可读的名字 24 25 """02班级表""" 26 class ClassList(models.Model): 27 #ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。 28 branch = models.ForeignKey("Branch",on_delete=models.CASCADE)#校区 关联到 校区表 29 course = models.ForeignKey("Course",on_delete=models.CASCADE) #课程 关联到 课程表 30 31 # ————————48PerfectCRM实现CRM客户报名流程学生合同———————— 32 contract = models.ForeignKey('ContractTemplate', blank=True, null=True, default=1,on_delete=models.CASCADE) # 合同表 33 # ————————48PerfectCRM实现CRM客户报名流程学生合同———————— 34 35 class_type_choices = ( #上课形式 36 (0,'面授(脱产)'), 37 (1,'面授(周末)'), 38 (2,'网络班'),) 39 #PositiveSmallIntegerField正小整数 0 ~ 32767 #choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作 40 class_type = models.SmallIntegerField(choices=class_type_choices)#上课形式 41 42 #PositiveSmallIntegerField正小整数 0 ~ 32767 43 semester = models.PositiveSmallIntegerField(verbose_name="学期") #课程的第几期 44 45 #ManyToManyField多对多和外键工作方式相同,只不过我们处理的是QuerySet而不是模型实例。 46 teachers = models.ManyToManyField("UserProfile") # 老师 关联到 账号表 47 48 start_date = models.DateField(verbose_name="开班日期") #DateField 日期格式 YYYY-MM-DD #verbose_name是Admin中显示的字段名称 49 50 # DateField 日期格式 YYYY-MM-DD #verbose_name是Admin中显示的字段名称 #Django可空#数据库可以为空 51 end_date = models.DateField(verbose_name="结业日期",blank=True,null=True) 52 53 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 54 return "%s %s %s" %(self.branch,self.course,self.semester) #返回 #%s格式化输出字符串 #校区#课程# 学期 55 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据 56 unique_together=('branch','course','semester') #联合索引 57 verbose_name_plural = "02班级表" #verbose_name_plural给你的模型类起一个更可读的名字 58 59 """03课程表,可以报名那些课程""" 60 class Course(models.Model): 61 name = models.CharField(max_length=64,unique=True)#课程名 #CharField作用是保存文本,定长的变量类型 62 price = models.PositiveSmallIntegerField(verbose_name="学费")#学费#PositiveSmallIntegerField正小整数 0 ~ 32767 63 period = models.PositiveSmallIntegerField(verbose_name="周期(月)") #PositiveSmallIntegerField正小整数 0 ~ 32767 64 outline = models.TextField() #课程大纲 #文本类型 65 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 66 return self.name #返回 #课程名 67 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据 68 verbose_name_plural = "03课程表"#verbose_name_plural给你的模型类起一个更可读的名字 69 70 '''04客户信息表''' 71 class Customer(models.Model): 72 name = models.CharField(max_length=32,blank=True,null=True)#客户名#CharField定长文本 #名字最长32 # Django可空 #数据库可以为空 73 qq = models.CharField(max_length=64,unique=True) #QQ号#CharField定长文本 #名字最长64 #唯一,不能重复 74 qq_name = models.CharField(max_length=64,blank=True,null=True)#QQ名 #CharField定长文本 #名字最长64 # Django可空 #数据库可以为空 75 phone = models.CharField(max_length=64,blank=True,null=True)#手机号 #CharField定长文本 #名字最长64 # Django可空 #数据库可以为空 76 77 # ————————48PerfectCRM实现CRM客户报名流程学生合同———————— 78 id_num=models.CharField(max_length=64,blank=True,null=True,verbose_name='身份证号')#身份证号 79 email=models.EmailField(max_length=64,blank=True,null=True,verbose_name='邮箱')#email 80 sex_choices=((0,'保密'),(1,'男'),(2,'女')) 81 sex=models.SmallIntegerField(choices=sex_choices,default=0,verbose_name='性别') 82 # ————————48PerfectCRM实现CRM客户报名流程学生合同———————— 83 84 # ————————53PerfectCRM实现CRM客户报名流程缴费———————— 85 status_choices = ((0, '已报名'), (1, '未报名'), (2, '已退学')) 86 status = models.SmallIntegerField(choices=status_choices, default=1) # 学员状态 87 # ————————53PerfectCRM实现CRM客户报名流程缴费———————— 88 89 source_choices = ( #客户渠道来源 (内存生成) 90 (0,'转介绍'), 91 (1,'QQ群'), 92 (2,'官网'), 93 (3,'百度推广'), 94 (4,'51CTO'), 95 (5,'知乎'), 96 (6,'市场推广'),) 97 #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作 98 source = models.SmallIntegerField(choices=source_choices)#客户渠道来源 99 100 #CharField定长文本#verbose_name是Admin中显示的字段名称#名字最长64 # Django可空 #数据库可以为空 101 referral_from = models.CharField(verbose_name="转介绍人qq",max_length=64,blank=True,null=True) #来自谁介绍的 102 103 #ForeignKey就是表与表之间的某种约定的关系#verbose_name是Admin中显示的字段名称 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。 104 consult_courses = models.ForeignKey("Course",verbose_name="咨询课程", on_delete=models.CASCADE) #关联到 课程表 105 106 content= models.TextField(verbose_name="咨询详情") #TextField无限制长度的文本#verbose_name是Admin中显示的字段名称 107 108 #ManyToManyField多对多和外键工作方式相同,只不过我们处理的是QuerySet而不是模型实例。 109 tags = models.ManyToManyField("Tag",blank=True)#多对多关联到 标签表 110 111 #ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。 112 consultant = models.ForeignKey("UserProfile", on_delete=models.CASCADE) #关联到 账号表 113 114 memo = models.TextField(blank=True,null=True)#备注#TextField无限制长度的文本#Django可空#数据库可以为空 115 116 #DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读) 117 date = models.DateTimeField(auto_now_add=True)#创建时间(数据库自增) 118 119 def __str__(self): #__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 120 return self.qq #返回 #QQ号 121 122 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据 123 verbose_name_plural = "04客户表" #verbose_name_plural给你的模型类起一个更可读的名字 124 125 # ————————48PerfectCRM实现CRM客户报名流程学生合同———————— 126 #合同模版 127 class ContractTemplate(models.Model): 128 name=models.CharField('合同名称',max_length=64,unique=True) 129 template=models.TextField() 130 131 def __str__(self): 132 return self.name 133 class Meta: 134 verbose_name_plural='合同表' 135 # ————————48PerfectCRM实现CRM客户报名流程学生合同———————— 136 137 138 """05客户跟进表""" 139 class CustomerFollowUp(models.Model): 140 141 #ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。 142 customer = models.ForeignKey("Customer", on_delete=models.CASCADE)#客户名 #关联到 客户信息表 143 144 content = models.TextField(verbose_name="跟进内容")#跟进的内容#TextField无限制长度的文本#verbose_name是Admin中显示的字段名称 145 146 #ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。 147 consultant =models.ForeignKey("UserProfile", on_delete=models.CASCADE) #关联到 账号表 148 149 intention_choices =( #报名状态 150 (0,'2周内报名'), 151 (1,'1个月内报名'), 152 (2,'近期无报名计划'), 153 (3,'已在其它机构报名'), 154 (4,'已报名'), 155 (5,'已拉黑'),) 156 #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作 157 intention=models.SmallIntegerField(choices=intention_choices) #报名状态 158 159 #DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读) 160 date = models.DateTimeField(auto_now_add=True)#创建时间(数据库自增) 161 162 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 163 return "<%s:%s>" %(self.customer.qq,self.intention) #返回#格式化字符串#跨表里的QQ号#报名状态 164 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据 165 verbose_name_plural = "05客户跟进表"#verbose_name_plural给你的模型类起一个更可读的名字 166 167 """06学员报名信息表""" 168 class Enrollment(models.Model): 169 # ForeignKey就是表与表之间的某种约定的关系#verbose_name是Admin中显示的字段名称 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。 170 customer = models.ForeignKey("Customer",on_delete=models.CASCADE)#学员名字 #关联到 客户信息表 171 enrolled_class = models.ForeignKey("ClassList",verbose_name="所报班级",on_delete=models.CASCADE)#关联到 班级表 172 consultant = models.ForeignKey("UserProfile",verbose_name="课程顾问",on_delete=models.CASCADE) #关联到 账号表 173 174 # ————————52PerfectCRM实现CRM客户报名流程学生合同审核———————— 175 contract_review = models.CharField(max_length=256, blank=True, null=True, verbose_name="合同审核") # 合同审核 176 # ————————52PerfectCRM实现CRM客户报名流程学生合同审核———————— 177 178 #BooleanField布尔值类型#default=False默认(True)不允许出现空字符#verbose_name是Admin中显示的字段名称 179 contract_agreed = models.BooleanField(default=False,verbose_name="学员已经同意合同")#学员看合同 180 contract_approved = models.BooleanField(default=False,verbose_name="合同已经审核") #谁审核 181 182 # ————————53PerfectCRM实现CRM客户报名流程缴费———————— 183 Pay_cost= models.BooleanField(default=False,verbose_name="缴费") #缴费状态#是不是交定金 184 # ————————53PerfectCRM实现CRM客户报名流程缴费———————— 185 186 # DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读) 187 date = models.DateTimeField(auto_now_add=True)#创建时间(数据库自增) 188 189 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 190 # ————————57PerfectCRM实现admin批量生成上课记录———————— 191 # return "%s %s" %(self.customer,self.enrolled_class)#返回#格式化字符串#学员名字#所报班级 192 return " 学员:%s |QQ: %s |班级:%s" %(self.customer.name,self.customer,self.enrolled_class)#返回#格式化字符串#学员名字#所报班级 193 # ————————57PerfectCRM实现admin批量生成上课记录———————— 194 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据 195 unique_together = ("customer","enrolled_class")#联合索引 196 verbose_name_plural = "06学员报名信息表"#verbose_name_plural给你的模型类起一个更可读的名字 197 198 """07缴费记录表""" 199 class Payment(models.Model): 200 #ForeignKey就是表与表之间的某种约定的关系#verbose_name是Admin中显示的字段名称 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。 201 customer = models.ForeignKey("Customer",on_delete=models.CASCADE)#学员名字 关联到 客户信息表 202 course = models.ForeignKey("Course",verbose_name="所报课程",on_delete=models.CASCADE)#关联到 课程表 203 204 #PositiveSmallIntegerField正小整数 0 ~ 32767 #verbose_name是Admin中显示的字段名称#默认值=500 205 amount = models.PositiveIntegerField(verbose_name="数额",default=500)#缴费数额 206 207 #ForeignKey就是表与表之间的某种约定的关系#CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。 208 consultant = models.ForeignKey("UserProfile",on_delete=models.CASCADE)#缴费给谁 关联到 账号表 #财务人员 209 210 #DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读) 211 date=models.DateTimeField(auto_now_add=True)#创建时间(数据库自增) 212 213 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 214 return "%s %s" %(self.customer,self.amount)#返回#格式化字符串#学员名字#缴费数额 215 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据 216 verbose_name_plural = "07缴费记录表"#verbose_name_plural给你的模型类起一个更可读的名字 217 218 """08每节课上课纪录表""" 219 class CourseRecord(models.Model): 220 # ForeignKey就是表与表之间的某种约定的关系#verbose_name是Admin中显示的字段名称 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。 221 from_class = models.ForeignKey("ClassList",verbose_name="班级",on_delete=models.CASCADE) #那个班级 222 223 #PositiveSmallIntegerField正小整数 0 ~ 32767 #verbose_name是Admin中显示的字段名称 224 day_num = models.PositiveSmallIntegerField(verbose_name="第几节(天)") #第几节课 225 226 # ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。 227 teacher = models.ForeignKey("UserProfile",on_delete=models.CASCADE)#老师是谁 关联到 账号表 228 229 #BooleanField布尔值类型#default=True默认(True)不允许出现空字符 230 has_homework = models.BooleanField(default=True) #有没有作业 231 232 # CharField定长文本#名字最长128#Django可空#数据库可以为空 233 homework_title = models.CharField(max_length=128,blank=True,null=True) #作业标题 234 235 #TextField无限制长度的文本#Django可空#数据库可以为空 236 homework_content = models.TextField(blank=True,null=True) #作业内容 237 238 #TextField无限制长度的文本#verbose_name是Admin中显示的字段名称 239 outline =models.TextField(verbose_name="本节课程大纲") #课程主要讲什么 240 241 # DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读) 242 date = models.DateField(auto_now_add=True)#创建时间(数据库自增) 243 244 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 245 return " %s:%s" %(self.from_class,self.day_num)#返回#格式化字符串#班级#第几节(天) 246 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据 247 unique_together = ("from_class","day_num") #联合索引 248 verbose_name_plural = "08每节课上课纪录表" #verbose_name_plural给你的模型类起一个更可读的名字 249 250 """09学习纪录""" 251 class StudyRecord(models.Model): 252 # ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。 253 student = models.ForeignKey("Enrollment",on_delete=models.CASCADE)#学生名字 关联到 学员报名信息表 254 course_record = models.ForeignKey("CourseRecord",on_delete=models.CASCADE)#开课记录 # 关联到 每节课上课纪录表 255 256 attendance_choices = (# 本节课上课状态记录 257 (0,"已签到"), 258 (1,"迟到"), 259 (2,"缺勤"), 260 (3,"早退"),) 261 #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作 262 attendance = models.SmallIntegerField(choices=attendance_choices) # 本节课上课状态记录 263 264 # ————————63PerfectCRM实现CRM讲师下载作业———————— 265 delivery = models.BooleanField(default=False,verbose_name="交作业") #有没有交付作业 266 # ————————63PerfectCRM实现CRM讲师下载作业———————— 267 268 269 # ————————61PerfectCRM实现CRM学生上传作业———————— 270 homework_link = models.TextField(blank=True,null=True)#作业链接 #TextField无限制长度的文本#Django可空#数据库可以为空 271 # ————————61PerfectCRM实现CRM学生上传作业———————— 272 273 score_choices = (#学习成绩 274 (100,"A+"), 275 (90,"A"), 276 (85,"B+"), 277 (80,"B"), 278 (75,"B-"), 279 (70,"C+"), 280 (65,"C"), 281 (40,"C-"), 282 (-20,"D"), 283 (-50,"COPY"), 284 (0,"N/A"),) 285 #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作 286 score = models.SmallIntegerField(choices=score_choices) #学习成绩 287 288 289 memo = models.TextField(blank=True,null=True)#TextField无限制长度的文本#Django可空#数据库可以为空 290 291 # DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读) 292 date = models.DateField(auto_now_add=True)#创建时间(数据库自增) 293 294 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 295 return "%s %s %s" % (self.student, self.course_record, self.score)#返回#格式化字符串#学生名字#开课记录#学习成绩 296 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据 297 unique_together = ('student','course_record')#联合索引#学生名字#开课记录 298 verbose_name_plural = "09学习纪录"#verbose_name_plural给你的模型类起一个更可读的名字 299 300 # ————————34PerfectCRM实现CRM自定义用户———————— 301 # """10账号表""" 302 # class UserProfile(models.Model): 303 # from django.contrib.auth.models import User # 使用django内置的用户表 304 # 305 # #OneToOneField一对一 #User是django Admin里的账号表#CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。 306 # user = models.OneToOneField(User,on_delete=models.CASCADE)# 用户名 #创建外键,关联django用户表 307 # 308 # name = models.CharField(max_length=32) #账号名(扩展用户字段)#CharField定长文本 309 # 310 # #ManyToManyField多对多和外键工作方式相同,只不过我们处理的是QuerySet而不是模型实例。#Django可空 311 # roles = models.ManyToManyField("Role",blank=True) #角色(权限) # 双向一对多==多对多 312 # 313 # def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 314 # return self.name #返回 #账号名 315 # class Meta: #通过一个内嵌类 "class Meta" 给你的 model 定义元数据 316 # verbose_name_plural = "10账号表"#verbose_name_plural给你的模型类起一个更可读的名字 317 # ————————34PerfectCRM实现CRM自定义用户———————— 318 319 # ————————34PerfectCRM实现CRM自定义用户———————— 320 #10账号表,创建用户和超级用户 321 from django.contrib.auth.models import BaseUserManager 322 class UserProfileManager(BaseUserManager): 323 def create_user(self, email, name, password=None): 324 """ 325 创建并保存一个用户用给定的邮件,日期 326 出生和密码。 327 """ 328 if not email:#没有email 报错 329 raise ValueError('用户必须有一个电子邮件地址') 330 331 user = self.model( 332 email=self.normalize_email(email),#验证邮箱格式 333 name=name, 334 ) 335 user.set_password(password)#加密 336 user.is_active = True 337 user.save(using=self._db) 338 return user 339 def create_superuser(self, email, name, password): 340 """ 341 创建并保存一个超级用户具有给定邮件,日期 342 出生和密码。 343 """ 344 user = self.create_user(email, 345 password=password, 346 name=name 347 ) 348 user.is_active = True 349 user.is_superuser = True 350 user.save(using=self._db) 351 return user 352 353 """10账号表""" 354 """ 355 356 #删除数据库 357 358 #调用objects = UserProfileManager()#创建账号 #关联这个函数 359 360 #运行 Terminal 361 # 生成 数据表 362 # python manage.py makemigrations 363 # 数据表 迁移 364 # python manage.py migrate 365 Django Admin里账号密码重置方法 366 #运行 Terminal 367 python manage.py createsuperuser 368 369 Email address: admin@qq.com 370 用户名 : admin 371 Password: admin123456 372 Password (again): admin123456 373 """ 374 from django.contrib.auth.models import AbstractBaseUser 375 # ————————35PerfectCRM实现CRM重写Admin密码修改———————— 376 from django.utils.translation import ugettext_lazy as _ # 语言国际化 377 from django.utils.safestring import mark_safe 378 from django.contrib.auth.models import PermissionsMixin 379 # class UserProfile(AbstractBaseUser): 380 class UserProfile(AbstractBaseUser,PermissionsMixin): 381 # ————————35PerfectCRM实现CRM重写Admin密码修改———————— 382 email=models.EmailField( 383 verbose_name='邮箱账号', 384 max_length=255, 385 unique=True#唯一 #登陆账号 386 ) 387 name=models.CharField(max_length=32,verbose_name='用户名') 388 389 390 # ————————72PerfectCRM实现CRM动态菜单和角色———————— 391 branch = models.ForeignKey( "Branch", verbose_name="所属校区", blank=True, null=True, on_delete=models.CASCADE ) 392 roles = models.ManyToManyField( 'Role', verbose_name="角色", blank=True ) 393 memo = models.TextField( blank=True, null=True, default=None, verbose_name="备注" ) 394 from django.utils import timezone 395 date_joined = models.DateTimeField( verbose_name="创建时间", default=timezone.now ) 396 # ————————72PerfectCRM实现CRM动态菜单和角色———————— 397 398 # ————————35PerfectCRM实现CRM重写Admin密码修改———————— 399 password = models.CharField(_('password'), max_length=128, help_text=mark_safe('''<a href=\"../password/\">修改密码</a>''')) 400 # ————————35PerfectCRM实现CRM重写Admin密码修改———————— 401 402 is_active = models.BooleanField(default=True,verbose_name='合法账号')#权限#合法账号 403 is_superuser = models.BooleanField(default=False,verbose_name='超级账号') #超级账号 404 objects = UserProfileManager()#创建账号 #关联这个函数 405 USERNAME_FIELD ='email'#指定做为 #登陆账号 406 REQUIRED_FIELDS = ['name']#必填字段 407 408 409 # ————————60PerfectCRM实现CRM学生上课记录———————— 410 stu_account = models.ForeignKey( "Customer", verbose_name='关联学员帐号', blank=True, null=True, on_delete=models.CASCADE, 411 help_text='报名成功后创建关联帐户' ) 412 # ————————60PerfectCRM实现CRM学生上课记录———————— 413 414 def get_full_name(self): 415 return self.email 416 def get_short_name(self): 417 #用户确认的电子邮件地址 418 return self.email 419 def __str__(self): 420 return self.name 421 def has_perm(self,perm,obj=None): 422 #指明用户是否被认为活跃的。以反选代替删除帐号。 423 #最简单的可能的答案:是的,总是 424 return True #有效 账号 425 def has_module_perms(self, app_label): 426 #指明用户是否可以登录到这个管理站点。 427 # 最简单的可能的答案:是的,总是 428 return True #职员状态 429 @property 430 def is_staff(self): 431 '''“用户的员工吗?”''' 432 #最简单的可能的答案:所有管理员都是员工 433 return self.is_superuser#是不是超级用户状态 434 # AUTH_USER_MODEL = 'crm.UserProfile'#使用自定的admin 表单 #settings.py 435 # ————————34PerfectCRM实现CRM自定义用户———————— 436 # ————————74PerfectCRM实现CRM权限和权限组限制URL———————— 437 class Meta: 438 verbose_name_plural = '10CRM账户表' 439 permissions = ( 440 ('crm_010101_all_table_data_list_GET', '010101_全部查看数据_GET'), 441 ('crm_010102_all_table_data_list_POST', '010102_全部查看数据_POST'), 442 ('crm_010103_all_table_add_GET', '010103_全部添加数据_GET'), 443 ('crm_010104_all_table_add_POST', '010104_全部添加数据_POST'), 444 ('crm_010105_all_table_change_GET', '010105_全部修改数据_GET'), 445 ('crm_010106_all_table_change_POST', '010106_全部修改数据_POST'), 446 ('crm_010107_all_table_delete_GET', '010107_全部删除数据_GET'), 447 ('crm_010108_all_table_delete_POST', '010108_全部删除数据_POST'), 448 ('crm_010109_all_password_reset_GET', '010109_全部密码重置_GET'), 449 ('crm_010110_all_password_reset_POST', '010110_全部密码重置_POST'), 450 451 ('crm_010201_only_view_Branch_GET', '010201_只能查看校区表_GET'), 452 ('crm_010202_only_view_Branch_POST', '010202_只能查看校区表_POST'), 453 ('crm_010203_only_add_Branch_GET', '010203_只能添加校区表_GET'), 454 ('crm_010204_only_add_Branch_POST', '010204_只能添加校区表_POST'), 455 ('crm_010205_only_change_Branch_GET', '010205_只能修改校区表_GET'), 456 ('crm_010206_only_change_Branch_POST', '010206_只能修改校区表_POST'), 457 ('crm_010207_only_delete_Branch_GET', '010207_只能删除校区表_GET'), 458 ('crm_010208_only_delete_Branch_POST', '010208_只能删除校区表_POST'), 459 460 ('crm_010301_only_view_ClassList_GET', '010301_只能查看班级表_GET'), 461 ('crm_010302_only_view_ClassList_POST', '010302_只能查看班级表_POST'), 462 ('crm_010303_only_add_ClassList_GET', '010303_只能添加班级表_GET'), 463 ('crm_010304_only_add_ClassList_POST', '010304_只能添加班级表_POST'), 464 ('crm_010305_only_change_ClassList_GET', '010305_只能修改班级表_GET'), 465 ('crm_010306_only_change_ClassList_POST', '010306_只能修改班级表_POST'), 466 ('crm_010307_only_delete_ClassList_GET', '010307_只能删除班级表_GET'), 467 ('crm_010308_only_delete_ClassList_POST', '010308_只能删除班级表_POST'), 468 469 ('crm_010401_only_view_Course_GET', '010401_只能查看课程表_GET'), 470 ('crm_010402_only_view_Course_POST', '010402_只能查看课程表_POST'), 471 ('crm_010403_only_add_Course_GET', '010403_只能添加课程表_GET'), 472 ('crm_010404_only_add_Course_POST', '010404_只能添加课程表_POST'), 473 ('crm_010405_only_change_Course_GET', '010405_只能修改课程表_GET'), 474 ('crm_010406_only_change_Course_POST', '010406_只能修改课程表_POST'), 475 ('crm_010407_only_delete_Course_GET', '010407_只能删除课程表_GET'), 476 ('crm_010408_only_delete_Course_POST', '010408_只能删除课程表_POST'), 477 478 ('crm_010501_only_view_Customer_GET', '010501_只能查看客户表_GET'), 479 ('crm_010502_only_view_Customer_POST', '010502_只能查看客户表_POST'), 480 ('crm_010503_only_add_Customer_GET', '010503_只能添加客户表_GET'), 481 ('crm_010504_only_add_Customer_POST', '010504_只能添加客户表_POST'), 482 ('crm_010505_only_change_Customer_GET', '010505_只能修改客户表_GET'), 483 ('crm_010506_only_change_Customer_POST', '010506_只能修改客户表_POST'), 484 ('crm_010507_only_delete_Customer_GET', '010507_只能删除客户表_GET'), 485 ('crm_010508_only_delete_Customer_POST', '010508_只能删除客户表_POST'), 486 487 ('crm_010601_only_view_CustomerFollowUp_GET', '010601_只能查看跟进表_GET'), 488 ('crm_010602_only_view_CustomerFollowUp_POST', '010602_只能查看跟进表_POST'), 489 ('crm_010603_only_add_CustomerFollowUp_GET', '010603_只能添加跟进表_GET'), 490 ('crm_010604_only_add_CustomerFollowUp_POST', '010604_只能添加跟进表_POST'), 491 ('crm_010605_only_change_CustomerFollowUp_GET', '010605_只能修改跟进表_GET'), 492 ('crm_010606_only_change_CustomerFollowUp_POST', '010606_只能修改跟进表_POST'), 493 ('crm_010607_only_delete_CustomerFollowUp_GET', '010607_只能删除跟进表_GET'), 494 ('crm_010608_only_delete_CustomerFollowUp_POST', '010608_只能删除跟进表_POST'), 495 496 ('crm_010701_only_view_Enrollment_GET', '010701_只能查看报名表_GET'), 497 ('crm_010702_only_view_Enrollment_POST', '010702_只能查看报名表_POST'), 498 ('crm_010703_only_add_Enrollment_GET', '010703_只能添加报名表_GET'), 499 ('crm_010704_only_add_Enrollment_POST', '010704_只能添加报名表_POST'), 500 ('crm_010705_only_change_Enrollment_GET', '010705_只能修改报名表_GET'), 501 ('crm_010706_only_change_Enrollment_POST', '010706_只能修改报名表_POST'), 502 ('crm_010707_only_delete_Enrollment_GET', '010707_只能删除报名表_GET'), 503 ('crm_010708_only_delete_Enrollment_POST', '010708_只能删除报名表_POST'), 504 505 ('crm_010801_only_view_Payment_GET', '010801_只能查看缴费表_GET'), 506 ('crm_010802_only_view_Payment_POST', '010802_只能查看缴费表_POST'), 507 ('crm_010803_only_add_Payment_GET', '010803_只能添加缴费表_GET'), 508 ('crm_010804_only_add_Payment_POST', '010804_只能添加缴费表_POST'), 509 ('crm_010805_only_change_Payment_GET', '010805_只能修改缴费表_GET'), 510 ('crm_010806_only_change_Payment_POST', '010806_只能修改缴费表_POST'), 511 ('crm_010807_only_delete_Payment_GET', '010807_只能删除缴费表_GET'), 512 ('crm_010808_only_delete_Payment_POST', '010808_只能删除缴费表_POST'), 513 514 ('crm_010901_only_view_CourseRecord_GET', '010901_只能查看上课表_GET'), 515 ('crm_010902_only_view_CourseRecord_POST', '010902_只能查看上课表_POST'), 516 ('crm_010903_only_add_CourseRecord_GET', '010903_只能添加上课表_GET'), 517 ('crm_010904_only_add_CourseRecord_POST', '010904_只能添加上课表_POST'), 518 ('crm_010905_only_change_CourseRecord_GET', '010905_只能修改上课表_GET'), 519 ('crm_010906_only_change_CourseRecord_POST', '010906_只能修改上课表_POST'), 520 ('crm_010907_only_delete_CourseRecord_GET', '010907_只能删除上课表_GET'), 521 ('crm_010908_only_delete_CourseRecord_POST', '010908_只能删除上课表_POST'), 522 523 ('crm_011001_only_view_StudyRecord_GET', '011001_只能查看学习表_GET'), 524 ('crm_011002_only_view_StudyRecord_POST', '011002_只能查看学习表_POST'), 525 ('crm_011003_only_add_StudyRecord_GET', '011003_只能添加学习表_GET'), 526 ('crm_011004_only_add_StudyRecord_POST', '011004_只能添加学习表_POST'), 527 ('crm_011005_only_change_StudyRecord_GET', '011005_只能修改学习表_GET'), 528 ('crm_011006_only_change_StudyRecord_POST', '011006_只能修改学习表_POST'), 529 ('crm_011007_only_delete_StudyRecord_GET', '011007_只能删除学习表_GET'), 530 ('crm_011008_only_delete_StudyRecord_POST', '011008_只能删除学习表_POST'), 531 532 ('crm_011101_only_view_UserProfile_GET', '011101_只能查看账号表_GET'), 533 ('crm_011102_only_view_UserProfile_POST', '011102_只能查看账号表_POST'), 534 ('crm_011103_only_add_UserProfile_GET', '011103_只能添加账号表_GET'), 535 ('crm_011104_only_add_UserProfile_POST', '011104_只能添加账号表_POST'), 536 ('crm_011105_only_change_UserProfile_GET', '011105_只能修改账号表_GET'), 537 ('crm_011106_only_change_UserProfile_POST', '011106_只能修改账号表_POST'), 538 ('crm_011107_only_delete_UserProfile_GET', '011107_只能删除账号表_GET'), 539 ('crm_011108_only_delete_UserProfile_POST', '011108_只能删除账号表_POST'), 540 541 ('crm_011201_only_view_Role_GET', '011201_只能查看角色表_GET'), 542 ('crm_011202_only_view_Role_POST', '011202_只能查看角色表_POST'), 543 ('crm_011203_only_add_Role_GET', '011203_只能添加角色表_GET'), 544 ('crm_011204_only_add_Role_POST', '011204_只能添加角色表_POST'), 545 ('crm_011205_only_change_Role_GET', '011205_只能修改角色表_GET'), 546 ('crm_011206_only_change_Role_POST', '011206_只能修改角色表_POST'), 547 ('crm_011207_only_delete_Role_GET', '011207_只能删除角色表_GET'), 548 ('crm_011208_only_delete_Role_POST', '011208_只能删除角色表_POST'), 549 550 ('crm_011301_only_view_Tag_GET', '011301_只能查看标签表_GET'), 551 ('crm_011302_only_view_Tag_POST', '011302_只能查看标签表_POST'), 552 ('crm_011303_only_add_Tag_GET', '011303_只能添加标签表_GET'), 553 ('crm_011304_only_add_Tag_POST', '011304_只能添加标签表_POST'), 554 ('crm_011305_only_change_Tag_GET', '011305_只能修改标签表_GET'), 555 ('crm_011306_only_change_Tag_POST', '011306_只能修改标签表_POST'), 556 ('crm_011307_only_delete_Tag_GET', '011307_只能删除标签表_GET'), 557 ('crm_011308_only_delete_Tag_POST', '011308_只能删除标签表_POST'), 558 559 ('crm_011401_only_view_FirstLayerMenu_GET', '011401_只能查看一层菜单_GET'), 560 ('crm_011402_only_view_FirstLayerMenu_POST', '011402_只能查看一层菜单_POST'), 561 ('crm_011403_only_add_FirstLayerMenu_GET', '011403_只能添加一层菜单_GET'), 562 ('crm_011404_only_add_FirstLayerMenu_POST', '011404_只能添加一层菜单_POST'), 563 ('crm_011405_only_change_FirstLayerMenu_GET', '011405_只能修改一层菜单_GET'), 564 ('crm_011406_only_change_FirstLayerMenu_POST', '011406_只能修改一层菜单_POST'), 565 ('crm_011407_only_delete_FirstLayerMenu_GET', '011407_只能删除一层菜单_GET'), 566 ('crm_011408_only_delete_FirstLayerMenu_POST', '011408_只能删除一层菜单_POST'), 567 568 ('crm_011501_only_view_SubMenu_GET', '011501_只能查看二层菜单_GET'), 569 ('crm_011502_only_view_SubMenu_POST', '011502_只能查看二层菜单_POST'), 570 ('crm_011503_only_add_SubMenu_GET', '011503_只能添加二层菜单_GET'), 571 ('crm_011504_only_add_SubMenu_POST', '011504_只能添加二层菜单_POST'), 572 ('crm_011505_only_change_SubMenu_GET', '011505_只能修改二层菜单_GET'), 573 ('crm_011506_only_change_SubMenu_POST', '011506_只能修改二层菜单_POST'), 574 ('crm_011507_only_delete_SubMenu_GET', '011507_只能删除二层菜单_GET'), 575 ('crm_011508_only_delete_SubMenu_POST', '011508_只能删除二层菜单_POST'), 576 577 ('crm_011601_only_view_Groups_GET', '011601_只能查看权限组_GET'), 578 ('crm_011602_only_view_Groups_POST', '011602_只能查看权限组_POST'), 579 ('crm_011603_only_add_Groups_GET', '011603_只能添加权限组_GET'), 580 ('crm_011604_only_add_Groups_POST', '011604_只能添加权限组_POST'), 581 ('crm_011605_only_change_Groups_GET', '011605_只能修改权限组_GET'), 582 ('crm_011606_only_change_Groups_POST', '011606_只能修改权限组_POST'), 583 ('crm_011607_only_delete_Groups_GET', '011607_只能删除权限组_GET'), 584 ('crm_011608_only_delete_Groups_POST', '011608_只能删除权限组_POST'), 585 586 ('crm_011701_own_password_reset_GET', '011701_自己密码重置_GET'), 587 ('crm_011702_own_password_reset_POST', '011702_自己密码重置_POST'), 588 589 ('crm_020101_all_not_audit_GET', '020101_销售查看全部的客户未审核_GET'), 590 ('crm_020103_all_enrollment_GET', '020103_销售给全部的客户报名课程_GET'), 591 ('crm_020104_all_enrollment_POST', '020104_销售给全部的客户报名课程_POST'), 592 ('crm_020105_all_contract_review_GET', '020105_销售给全部的客户审核合同_GET'), 593 ('crm_020116_all_contract_review_POST', '020116_销售给全部的客户审核合同_POST'), 594 595 ('crm_020201_own_enrollment_GET', '020201_销售给自己的客户报名课程_GET'), 596 ('crm_020202_own_enrollment_POST', '020202_销售给自己的客户报名课程_POST'), 597 ('crm_020203_own_contract_review_GET', '020203_销售给自己的客户审核合同_GET'), 598 ('crm_020204_own_contract_review_POST', '020204_销售给自己的客户审核合同_POST'), 599 600 ('crm_030101_all_not_payment_GET', '030101_财务查看全部的客户未缴费_GET'), 601 ('crm_030102_all_not_payment_POST', '030102_财务查看全部的客户未缴费_POST'), 602 ('crm_030103_all_already_payment_GET', '030103_财务查看全部的客户已缴费_GET'), 603 ('crm_030104_all_already_payment_POST', '030104_财务查看全部的客户已缴费_POST'), 604 ('crm_030105_all_payment_GET', '030105_财务进行全部的客户缴费_GET'), 605 ('crm_030106_all_payment_POST', '030106_财务进行全部的客户缴费_POST'), 606 607 ('crm_040101_own_student_course_GET', '040101_学生查看自己的课程_GET'), 608 ('crm_040102_own_student_course_POST', '040102_学生查看自己的课程_POST'), 609 ('crm_040103_own_studyrecords_GET', '040103_学生自己的上课记录_GET'), 610 ('crm_040104_own_studyrecords_POST', '040104_学生自己的上课记录_POST'), 611 ('crm_040105_own_homework_detail_GET', '040105_学生自己的作业详情_GET'), 612 ('crm_040106_own_homework_detail_POST', '040106_学生自己的作业详情_POST'), 613 614 ('crm_050101_own_teacher_class_GET', '050101_讲师查看自己的班级_GET'), 615 ('crm_050102_own_teacher_class_POST', '050102_讲师查看自己的班级_POST'), 616 ('crm_050103_own_teacher_class_detail_GET', '050103_讲师查看自己的课节详情_GET'), 617 ('crm_050104_own_teacher_class_detail_POST', '050104_讲师查看自己的课节详情_POST'), 618 ('crm_050105_own_teacher_lesson_detail_GET', '050105_讲师查看自己的课节学员_GET'), 619 ('crm_050106_own_teacher_lesson_detail_POST', '050106_讲师查看自己的课节学员_POST'), 620 ('crm_050107_own_howk_down_GET', '050107_讲师自己的学员作业下载_GET'), 621 ('crm_050108_own_howk_down_POST', '050108_讲师自己的学员作业下载_POST'), 622 623 ('crm_060101_own_coursetop_details_GET', '060101_讲师查看自己的班级排名详情_GET'), 624 ('crm_060102_own_coursetop_details_POST', '060102_讲师查看自己的班级排名详情_POST'), 625 ('crm_060103_own_coursetop_score_GET', '060103_讲师查看自己的班级分数排行_GET'), 626 ('crm_060104_own_coursetop_score_POST', '060104_讲师查看自己的班级排分数排行_POST'), 627 ('crm_060105_own_coursetop_homework_GET', '060105_讲师查看自己的班级作业排行_GET'), 628 ('crm_060106_own_coursetop_homework_POST', '060106_讲师查看自己的班级作业排行_POST'), 629 ('crm_060107_own_coursetop_attendance_GET', '060107_讲师查看自己的班级出勤排行_GET'), 630 ('crm_060108_own_coursetop_attendance_POST', '060108_讲师查看自己的班级出勤排行_POST'), 631 632 ) 633 # ————————74PerfectCRM实现CRM权限和权限组限制URL———————— 634 # ————————74PerfectCRM实现CRM权限和权限组限制URL———————— 635 """15权限组""" 636 from django.contrib.auth.models import Group 637 class Groups(Group): 638 class Meta: 639 verbose_name_plural = '15权限组' 640 # ————————74PerfectCRM实现CRM权限和权限组限制URL———————— 641 # ————————75PerfectCRM实现CRM扩展权限———————— 642 from django.contrib.auth.models import Permission 643 class Permissions(Permission): 644 dic_name = models.CharField(_('dic_name'), max_length=255) 645 class Meta: 646 verbose_name_plural = "16扩展权限" 647 # ————————75PerfectCRM实现CRM扩展权限———————— 648 649 650 """11角色表""" 651 class Role(models.Model): 652 name = models.CharField(unique=True,max_length=32)#角色名#CharField定长文本#角色名不可以重复#最长度=32字节 653 654 # ————————72PerfectCRM实现CRM动态菜单和角色———————— 655 menus = models.ManyToManyField('FirstLayerMenu',verbose_name='一层菜单',blank=True) 656 # ————————72PerfectCRM实现CRM动态菜单和角色———————— 657 658 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 659 return self.name#返回 #角色名 660 class Meta: #通过一个内嵌类 "class Meta" 给你的 model 定义元数据 661 verbose_name_plural = "11角色表" #verbose_name_plural给你的模型类起一个更可读的名字 662 663 664 """12标签表""" 665 class Tag(models.Model): 666 name = models.CharField(max_length=64,unique=True) #标签名#CharField定长文本#最长度=64字节#不可以重复 667 def __str__(self): #__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 668 return self.name #返回 #标签名 669 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据 670 verbose_name_plural = "12标签表" #verbose_name_plural给你的模型类起一个更可读的名字 671 672 # ————————01PerfectCRM基本配置ADMIN———————— 673 674 675 # ————————72PerfectCRM实现CRM动态菜单和角色———————— 676 """13一层菜单名""" 677 class FirstLayerMenu(models.Model): 678 '''第一层侧边栏菜单''' 679 name = models.CharField('一层菜单名',max_length=64) 680 url_type_choices = ((0,'相关的名字'),(1,'固定的URL')) 681 url_type = models.SmallIntegerField(choices=url_type_choices,default=0) 682 url_name = models.CharField(max_length=64,verbose_name='一层菜单路径') 683 order = models.SmallIntegerField(default=0,verbose_name='菜单排序') 684 sub_menus = models.ManyToManyField('SubMenu',blank=True) 685 686 def __str__(self): 687 return self.name 688 689 class Meta: 690 verbose_name_plural = "13第一层菜单" 691 692 """14二层菜单名""" 693 class SubMenu(models.Model): 694 '''第二层侧边栏菜单''' 695 name = models.CharField('二层菜单名', max_length=64) 696 url_type_choices = ((0,'相关的名字'),(1,'固定的URL')) 697 url_type = models.SmallIntegerField(choices=url_type_choices,default=0) 698 url_name = models.CharField(max_length=64, verbose_name='二层菜单路径') 699 order = models.SmallIntegerField(default=0, verbose_name='菜单排序') 700 701 def __str__(self): 702 return self.name 703 704 class Meta: 705 verbose_name_plural = "14第二层菜单" 706 # ————————72PerfectCRM实现CRM动态菜单和角色————————
1 # kingadmin.py 2 # ————————04PerfectCRM实现King_admin注册功能———————— 3 from crm import models 4 #print("kingadmin crm",models.Customer) 5 6 # ————————05PerfectCRM实现King_admin注册功能获取内存———————— 7 # from king_admin.base_admin import register,BaseAdmin 8 from king_admin.base_admin import site,BaseAdmin 9 # ————————05PerfectCRM实现King_admin注册功能获取内存———————— 10 11 # ————————24PerfectCRM实现King_admin自定义操作数据———————— 12 from django.shortcuts import render 13 # ————————24PerfectCRM实现King_admin自定义操作数据———————— 14 15 # ————————28PerfectCRM实现King_admin编辑限制———————— 16 from django.forms import ValidationError 17 from django.shortcuts import render,redirect 18 # ————————28PerfectCRM实现King_admin编辑限制———————— 19 20 21 22 23 # ————————62PerfectCRM实现CRM讲师讲课记录———————— 24 # 02班级表 25 class ClassListAdmin(BaseAdmin): 26 list_display = ['id', 'branch', 'course', 'class_type', 'semester', 'start_date', 'end_date'] # 显示字段表头 27 list_filter = ['branch', 'course', 'class_type'] # 过滤器(可以包含ManyToManyField) (注意加 逗号 , ) 28 filter_horizontal = ['teachers'] #复选框 29 site.register(models.ClassList,ClassListAdmin) #02班级表 30 31 # ————————62PerfectCRM实现CRM讲师讲课记录———————— 32 33 34 35 36 #04客户信息表 37 class CustomerAdmin(BaseAdmin):#定制Djanago admin 38 # ————————54PerfectCRM实现CRM客户报名链接———————— 39 # list_display = ('id', 'qq', 'source', 'consultant', 'content', 'date') # 显示字段表头 40 list_display = ('id', 'qq', 'source', 'consultant', 'content', 'date','status','enroll') # 显示字段表头 41 # ————————54PerfectCRM实现CRM客户报名链接———————— 42 # ————————11PerfectCRM实现King_admin分页显示条数———————— 43 list_per_page = 2 #分页条数 # 默认分页条数10 44 # ————————11PerfectCRM实现King_admin分页显示条数———————— 45 # ————————16PerfectCRM实现King_admin日期过滤———————— 46 # ————————15PerfectCRM实现King_admin多条件过滤———————— 47 # 过滤器(可以包含ManyToManyField) (注意加 逗号 , ) 48 # list_filter = ('source','consultant','consult_courses',) 49 list_filter = ('date','source','consultant','consult_courses',) 50 # ————————15PerfectCRM实现King_admin多条件过滤———————— 51 # ————————16PerfectCRM实现King_admin日期过滤———————— 52 # ————————18PerfectCRM实现King_admin搜索关键字———————— 53 #搜索(不能包含CharField)(注意加 逗号 , ) 54 search_fields = ('name','qq',) 55 # ————————18PerfectCRM实现King_admin搜索关键字———————— 56 # ————————26PerfectCRM实现King_admin自定义排序———————— 57 ordering = '-qq' #自定义排序,默认'-id' 58 # ————————26PerfectCRM实现King_admin自定义排序———————— 59 # ————————27PerfectCRM实现King_admin编辑复选框———————— 60 filter_horizontal = ('tags',) #复选框 61 # ————————27PerfectCRM实现King_admin编辑复选框———————— 62 # ————————33PerfectCRM实现King_admin编辑整张表限制———————— 63 readonly_table=True#默认表单不锁定 64 # ————————33PerfectCRM实现King_admin编辑整张表限制———————— 65 66 # ————————55PerfectCRM实现CRM客户报名状态颜色变化———————— 67 colored_fields = { 68 'status':{'已报名':"rgba(145, 255, 0, 0.78)", 69 '未报名':"#ddd"},} 70 # ————————55PerfectCRM实现CRM客户报名状态颜色变化———————— 71 72 # ————————54PerfectCRM实现CRM客户报名链接———————— 73 def enroll(self): 74 '''报名''' 75 print("customize field enroll",self) 76 link_name = "报名" 77 if self.instance.status == 0: 78 link_name = "报名新课程" 79 return '''<a target="_blank" class="btn-link" href="/bpm/customer/%s/enrollment/">点击%s</a> ''' % (self.instance.id,link_name) 80 # url(r'^customer/(\d+)/enrollment/$', sales_views.enrollment, name="enrollment"), # 客户招生#报名流程一 下一步 81 # target属性用于表示所链接文件打开到的位置 #记住,“”内的文字只是表示一个对象的名子。 82 enroll.display_name = "报名链接" 83 # ————————54PerfectCRM实现CRM客户报名链接———————— 84 85 86 87 # ————————24PerfectCRM实现King_admin自定义操作数据———————— 88 # from django.shortcuts import render 89 actions = ['test_actions',]#定制功能 #测试返回到一个新页面 90 def test_actions(self,request,arg2):#对应的函数 #request类自己的请求 #arg2类的内容 91 return render(request,"king_admin/table_index.html") 92 test_actions.short_description = "测试显示中文" 93 # ————————24PerfectCRM实现King_admin自定义操作数据———————— 94 95 # ————————28PerfectCRM实现King_admin编辑限制———————— 96 # ————————31PerfectCRM实现King_admin编辑多对多限制———————— 97 # readonly_fields = ('qq', 'consultant',) # 不可修改 98 readonly_fields = ('qq', 'consultant','tags',) # 不可修改 99 # ————————31PerfectCRM实现King_admin编辑多对多限制———————— 100 101 # ————————29PerfectCRM实现King_admin编辑自定义限制———————— 102 def default_form_validation(self,obj): 103 print('validation:制定的',obj.cleaned_data) 104 consult_course=obj.cleaned_data.get('content','')#自制验证字段 105 if len(consult_course)<10: 106 return ValidationError(#添加错误信息 返回 107 ("该字段%(field)s 咨询内容记录不能少于10个字符"), 108 code='invalid', 109 params={'field':'content',}, 110 ) 111 # ————————29PerfectCRM实现King_admin编辑自定义限制———————— 112 113 # ————————28PerfectCRM实现King_admin编辑限制———————— 114 115 # ————————30PerfectCRM实现King_admin编辑自定义字段验证———————— 116 def clean_name(self,obj,*args,**kwargs):#名称验证 单个 117 name=obj.cleaned_data['name'] 118 if not name: 119 obj.add_error('name','不能为空!') 120 return ValidationError(#添加错误信息 返回 121 ("%(field)s:该字段 不能为空"), 122 code='invalid', 123 params={'field':'name',}, 124 ) 125 elif len(name)<5: 126 obj.add_error('name','不能小于5个字符!') 127 #return ValidationError('',) 128 return ValidationError(#添加错误信息 返回 129 ("%(field)s:该字段 不能小于5个字符!"), 130 code='invalid', 131 params={'field':'name',}, 132 ) 133 # ————————30PerfectCRM实现King_admin编辑自定义字段验证———————— 134 135 # ————————34PerfectCRM实现CRM自定义用户———————— 136 #10账号表 137 class UserProfileAdmin(BaseAdmin):#定制Djanago admin 138 list_display = ('id', 'email', 'name') # 显示字段表头 139 140 # ————————36PerfectCRM实现King_admin密码修改———————— 141 readonly_fields = ('password',) # 不可修改,限制 142 143 # ————————72PerfectCRM实现CRM动态菜单和角色———————— 144 # filter_horizontal = ('user_permissions','groups') #复选框 145 filter_horizontal = ('user_permissions', 'groups','roles') # 复选框 146 # ————————72PerfectCRM实现CRM动态菜单和角色———————— 147 148 modelform_exclude_fields=['last_login']#排除#不显示 #自增日期 #base_admin.py #forms.py 149 # ————————36PerfectCRM实现King_admin密码修改———————— 150 151 site.register(models.UserProfile, UserProfileAdmin) 152 # ————————34PerfectCRM实现CRM自定义用户———————— 153 154 # ————————05PerfectCRM实现King_admin注册功能获取内存———————— 155 # register(models.Customer,CustomerAdmin) 156 # register(models.CourseRecord) 157 site.register(models.Customer,CustomerAdmin) 158 # ————————58PerfectCRM实现king_admin批量生成上课记录———————— 159 # site.register(models.CourseRecord) 160 # ————————58PerfectCRM实现king_admin批量生成上课记录———————— 161 # ————————05PerfectCRM实现King_admin注册功能获取内存———————— 162 163 # ————————04PerfectCRM实现King_admin注册功能———————— 164 165 166 # ————————56PerfectCRM实现CRM客户报名缴费链接———————— 167 # 06学员报名信息表 168 class EnrollmentAdmin(BaseAdmin): # 定制Djanago admin 169 list_display = ('id', 'customer', 'enrolled_class', 'consultant', 'Pay_cost', 'date', 'payment') # 显示字段表头 170 171 # ————————58PerfectCRM实现king_admin批量生成上课记录———————— 172 list_filter = ('enrolled_class','consultant', 'Pay_cost',) # 过滤器(可以包含ManyToManyField) (注意加 逗号 , ) 173 # ————————58PerfectCRM实现king_admin批量生成上课记录———————— 174 175 colored_fields = { 176 'Pay_cost': {True: "rgba(145, 255, 0, 0.78)", 177 False: "#ddd"}, } 178 def payment(self): 179 link_name = "增加缴费" 180 if self.instance.Pay_cost == False: 181 link_name = "缴费" 182 return '''<a target="_blank" class="btn-link" href="/bpm/payment/%s/" >点击%s</a> ''' % (self.instance.id, link_name) 183 # url(r'^payment/(\d+)/$', financial_views.payment, name="payment"), # 报名流程四 缴费 #财务 184 # target属性用于表示所链接文件打开到的位置 #记住,“”内的文字只是表示一个对象的名子。 185 payment.display_name = "缴费链接" 186 site.register(models.Enrollment, EnrollmentAdmin) # 06学员报名信息表 187 # ————————56PerfectCRM实现CRM客户报名缴费链接———————— 188 189 # ————————58PerfectCRM实现king_admin批量生成上课记录———————— 190 # 07缴费记录表 191 class PaymentAdmin(BaseAdmin): 192 list_display = ['id', 'customer', 'course', 'amount', 'consultant','date'] # 显示字段表头 193 list_filter = ('customer', 'course', 'consultant',) # 过滤器(可以包含ManyToManyField) (注意加 逗号 , ) 194 195 from django.shortcuts import render, HttpResponse, redirect 196 # 08每节课上课纪录表 197 class CourseRecordAdmin(BaseAdmin): 198 list_display = ['id', 'from_class', 'day_num', 'teacher', 'has_homework', 'homework_title', 'homework_content','outline', 'date'] # 显示字段表头 199 list_filter = ('from_class', 'teacher', 'date') # 过滤器(可以包含ManyToManyField) (注意加 逗号 , ) 200 def initialize_studyrecords(self, request, queryset): # 制定功能 201 print('initialize_studyrecords', self, request, queryset) 202 if len(queryset) > 1: 203 return HttpResponse("同时只能选择一个班级!") 204 print('获取对应的学员', queryset[0].from_class.enrollment_set.all()) # _set反向查询 205 new_obj_list = [] # 用于批量创建事务 #防止数据库事物回滚 206 for enrll_obj in queryset[0].from_class.enrollment_set.all(): # 创建学习记录 207 # models.StudyRecord.objects.get_or_create( #get_or_ #防止报错 208 # student=enrll_obj,#对应学员 209 # course_record=queryset[0], 210 # attendance=0,#签到状态,默认签到, 211 # score=0,#成绩 212 # ) 213 214 # 防止数据库事物回滚 #"""09学习纪录""" 215 new_obj_list.append(models.StudyRecord( 216 student=enrll_obj, # 对应学员 217 course_record=queryset[0], # 班级#节课 218 attendance=0, # 签到状态,默认签到, 219 score=0, # 成绩 220 )) 221 try: 222 models.StudyRecord.objects.bulk_create(new_obj_list) # bulk_create批量创建数据库事物 #统一最后保存 223 except Exception as e: 224 return HttpResponse('批量创建失败,本节课可能有相应的上课记录') 225 226 return redirect("/king_admin/crm/studyrecord/?course_record=%s" % queryset[0].id) # 学习记录 #加上过滤 227 228 actions = ['initialize_studyrecords', ] 229 initialize_studyrecords.short_description = "创建班级本节上课记录" # 显示别名 230 # 09学习纪录 231 class StudyRecordAdmin(BaseAdmin): 232 list_display = ['id', 'student', 'course_record', 'attendance', 'score', 'date'] # 显示字段表头 233 234 list_filter = ['course_record', 'attendance', 'score', 'student'] # 过滤器(可以包含ManyToManyField) (注意加 逗号 , ) 235 236 list_editable = ['score', 'attendance'] # 可编辑 #用于上课点名 批改成绩 237 238 site.register(models.Payment, PaymentAdmin) # 07缴费记录表 239 site.register(models.CourseRecord, CourseRecordAdmin) # 08每节课上课纪录表 240 site.register(models.StudyRecord, StudyRecordAdmin) # 09学习纪录 241 # ————————58PerfectCRM实现king_admin批量生成上课记录———————— 242 243 244 # ————————72PerfectCRM实现CRM动态菜单和角色———————— 245 # 11角色表 246 class RoleAdmin(BaseAdmin): 247 list_display = ['id', 'name'] # 显示字段表头 248 filter_horizontal = ['menus'] # 复选框 249 site.register(models.Role,RoleAdmin) #11角色表 250 251 # 13一层菜单名 252 class FirstLayerMenuAdmin(BaseAdmin): 253 list_display = ['id', 'name', 'url_type', 'url_name', 'order'] # 显示字段表头 254 site.register(models.FirstLayerMenu,FirstLayerMenuAdmin) #13一层菜单名 255 # 14二层菜单名 256 class SubMenuMenuAdmin(BaseAdmin): 257 list_display = ['id', 'name', 'url_type', 'url_name', 'order'] # 显示字段表头 258 site.register(models.SubMenu,SubMenuMenuAdmin) #14二层菜单名 259 # ————————72PerfectCRM实现CRM动态菜单和角色———————— 260 261 # ————————74PerfectCRM实现CRM权限和权限组限制访问URL———————— 262 class GroupsAdmin(BaseAdmin): 263 list_display = ['id', 'name'] # 显示字段表头 264 filter_horizontal = ['permissions'] # 复选框 265 site.register(models.Groups,GroupsAdmin) #14二层菜单名 266 # ————————74PerfectCRM实现CRM权限和权限组限制访问URL———————— 267 268 # ————————75PerfectCRM实现CRM扩展权限———————— 269 class PermissionsAdmin(BaseAdmin): 270 list_display = ['id', 'name','codename','dic_name'] # 显示字段表头 271 site.register(models.Permissions,PermissionsAdmin) #16扩展权限 272 # ————————75PerfectCRM实现CRM扩展权限————————
1 # permission.py 2 # ————————74PerfectCRM实现CRM权限和权限组限制URL———————— 3 from django.urls import resolve # resolve解析URL 4 from django.shortcuts import render,redirect,HttpResponse #页面返回 5 from permissions.permission_list import perm_dic #权限字典 6 # ————————75PerfectCRM实现CRM扩展权限———————— 7 import json #字符串转列表 8 from crm import models #数据库查询扩展的权限 9 from permissions.ECJ import * #扩展的自定义函数 10 # ————————75PerfectCRM实现CRM扩展权限———————— 11 def perm_check(*args,**kwargs): 12 print( '执行perm_check:', *args, **kwargs ) 13 request = args[0]# 14 # print(request) #<WSGIRequest: GET '/king_admin/crm/firstlayermenu/4/change/'> 15 16 resolve_url_obj = resolve(request.path)#反解URL路径#获取当前的URL# resolve解析URL#生成实例 17 print('反解URL路径:',resolve_url_obj)#ResolverMatch(func=permissions.permission.inner, args=('crm', 'firstlayermenu', '4'), kwargs={}, url_name=table_change, app_names=[], namespaces=[]) 18 current_url_name = resolve_url_obj.url_name # 当前url的url_name 19 print('当前用户:',request.user,'当前url的url_name:',current_url_name)#admin2 当前url的url_name: table_change 20 21 permission_list= request.user.user_permissions.values_list('codename') # 根据 登陆的ID 获取 拥有的权限列表 22 print('拥有的权限列表',permission_list) 23 24 permission_group = request.user.groups.all().values_list('permissions__codename') # 根据 登陆的ID 获取 拥有的组 25 print('拥有的权限组',permission_group) 26 27 match_key = None 28 match_results = [False,] #后面会覆盖,加个False是为了让all(match_results)不出错 29 30 # ————————75PerfectCRM实现CRM扩展权限———————— 31 print('permission_list',perm_dic) #permission_list 32 models_dic = dict(models.Permissions.objects.values_list( 'codename', 'dic_name' ))#查询数据库 33 print( 'models_dic', models_dic ) 34 perm_dic.update(models_dic) #扩展权限字典 35 print( '扩展后的权限字典', perm_dic ) 36 # ————————75PerfectCRM实现CRM扩展权限———————— 37 38 for permission_key,permission_val in perm_dic.items():#从权限字典中取相关字段 #crm_table_index':['1','table_index','GET',[],{},], 39 # print('循环权限表',((permission_key),)) 40 if ((permission_key),) in permission_list or ((permission_key),) in permission_group:#权限列表是元组 41 # ————————75PerfectCRM实现CRM扩展权限———————— 42 if type( permission_val ).__name__ in ['str']: 43 permission_val = json.loads( permission_val ) # 字符串转列表 44 # ————————75PerfectCRM实现CRM扩展权限———————— 45 46 per_url_name = permission_val[0] #URL 47 per_method = permission_val[1] #GET #POST #请求方法 48 perm_args = permission_val[2] # 列表参数 49 perm_kwargs = permission_val[3]# 字典参数 50 51 # ————————75PerfectCRM实现CRM扩展权限———————— 52 # custom_perm_func = None if len(permission_val) == 4 else permission_val[4] #url判断 #自定义权限钩子 53 if len( permission_val ) == 4 : 54 custom_perm_func = None 55 else: 56 if type( permission_val[4] ).__name__ in ['str']: 57 custom_perm_func = globals().get( permission_val[4] ) # url判断 #自定义权限钩子 58 else: 59 custom_perm_func = permission_val[4] 60 # ————————75PerfectCRM实现CRM扩展权限———————— 61 62 # 'crm_can_access_my_clients':['table_list','GET',[],{'perm_check':33,'arg2':'test'}, custom_perm_logic.only_view_own_customers], 63 # print('URL:',per_url_name,'请求方法:',per_method,'列表参数:',perm_args,'字典参数:',perm_kwargs,'自定义权限钩子:',custom_perm_func) 64 65 66 if per_url_name == current_url_name: #权限字典的 URL ==当前请求的url #crm_table_index':['URL','请求方法',[列表参数],{字典参数},], 67 if per_method == request.method: #权限字典的 请求方法 == 当前请求的方法 #crm_table_index':['URL','请求方法',[列表参数],{字典参数},], 68 #逐个匹配参数,看每个参数时候都能对应的上。 69 args_matched = False #参数匹配 #仅供参数 70 for item in perm_args: #循环列表参数 #crm_table_index':['URL','请求方法',[列表参数],{字典参数},], 71 request_method_func = getattr(request,per_method) #反射 #请求方法 #GET #POST 72 if request_method_func.get(item,None):# 如果request字典中有此参数 73 args_matched = True 74 else: 75 print("参数不匹配......") 76 args_matched = False 77 break # 有一个参数不能匹配成功,则判定为假,退出该循环。 78 else: 79 args_matched = True #没有执行 break 表示 列表匹配成功 #防止列表没有使用参数时出错 80 81 #匹配有特定值的参数 82 kwargs_matched = False 83 for k,v in perm_kwargs.items(): #循环字典参数#crm_table_index':['URL','请求方法',[列表参数],{字典参数},], 84 request_method_func = getattr(request, per_method) #反射 #请求方法 #GET #POST 85 arg_val = request_method_func.get(k, None) # request字典中有此参数 86 print("perm kwargs check:",arg_val,type(arg_val),v,type(v)) 87 if arg_val == str(v): #匹配上了特定的参数 及对应的 参数值, 比如,需要request 对象里必须有一个叫 user_id=3的参数 88 kwargs_matched = True 89 else: 90 kwargs_matched = False 91 break # 有一个参数不能匹配成功,则判定为假,退出该循环。 92 else: 93 kwargs_matched = True 94 95 96 #自定义权限钩子 97 perm_func_matched = False 98 if custom_perm_func: #如果有定义 99 if custom_perm_func(request,args,kwargs):#def only_view_own_customers(request,*args,**kwargs): 100 perm_func_matched = True 101 else: 102 perm_func_matched = False #使整条权限失效 103 print('自定义权限钩子没有通过',perm_func_matched) 104 else: #没有定义权限钩子,所以默认通过 105 perm_func_matched = True 106 107 match_results = [args_matched,kwargs_matched,perm_func_matched] #列表 108 print("匹配结果: ", match_results) # [True, True, True] 109 if all(match_results): #都匹配上了 #都返回 True 110 match_key = permission_key # 给 match_key = None 赋值 111 break #跳出大循环 112 113 if all(match_results): #如果都匹配成功 #'crm_table_index':['table_index','GET',[],{},], 114 app_name, *per_name = match_key.split('_') #先给app_name赋一个值,其他的值都给*per_name 'crm_table_index': 115 print("权限名:",match_key,'权限:',match_results)#crm_010902_only_view_CourseRecord_POST [True, True, True] 116 print('分割:',app_name, *per_name) # crm 010902 only view CourseRecord POST 117 perm_obj = '%s.%s' % (app_name,match_key)#'crm.table_index' # url(r'^(\w+)/$', views.table_index, name='table_index'), # 单个具体app页面 118 print("生成权限:",perm_obj) #crm.crm_010902_only_view_CourseRecord_POST 119 if request.user.has_perm(perm_obj): 120 print('当前用户有此权限') 121 return True 122 else: 123 print('当前用户没有该权限') 124 return False 125 else: 126 print("未匹配到权限项,当前用户无权限") 127 128 def check_permission(func): 129 print('权限func',func)#权限func <function table_data_list at 0x030636A8> #循环 URL name 130 def inner(*args,**kwargs): 131 print('开始权限匹配:',type(args)) 132 request = args[0]#请求第一个 133 print('判断登陆情况:') 134 if request.user.id == None: 135 print('未登陆') 136 return redirect( '/gbacc/gbacc_login/' )#返回登陆页面 137 else: 138 if request.user.is_superuser == True: 139 print('超级管理员') 140 return func( *args, **kwargs ) #直接返回 真 141 print( '已登陆,判断有perm_check(*args,**kwargs)去执行' ) 142 if not perm_check(*args,**kwargs): #如果返回不为真 #没权限 143 print('#没权限',perm_check(*args,**kwargs)) 144 request = args[0] 145 return HttpResponse('你没有这个权限') 146 print('有权限',func(*args,**kwargs)) #<HttpResponse status_code=200, "text/html; charset=utf-8"> 147 return func(*args,**kwargs) 148 print('inner',inner) 149 return inner #返回 真或假 150 # ————————74PerfectCRM实现CRM权限和权限组限制URL————————
1 # ECJ.py 2 # ————————75PerfectCRM实现CRM扩展权限———————— 3 import re #正则 4 5 #070101_查看自己的客户表_GET 6 def view_own_Customer(request,*args,**kwargs): 7 url_path = request.path #获取URL 路径 8 url_list=re.findall('(\w+)',url_path) #正者表达式 获取参数 9 url_model_name= url_list[2] #字符串 10 model_name = 'customer'#字符串 11 if url_model_name==model_name: #防止其他表通过权限 12 consultant_id = request.GET.get('consultant') #过滤条件 &consultant=7 13 if consultant_id: 14 consultant_id = int(consultant_id) #转换成 数字 15 if consultant_id == request.user.id: # 账号表 的ID 等于 #当前登陆的ID 16 return True 17 else: 18 return False 19 else: 20 return False 21 22 #070103_修改自己的客户表_GET 23 #070105_删除自己的客户表_GET 24 def change_own_Customer(request,*args,**kwargs): 25 url_path = request.path #获取URL 路径 26 url_list=re.findall('(\w+)',url_path) #正者表达式 获取参数 27 url_model_name= url_list[2] 28 url_parameter =int(url_list[3]) 29 model_name = 'customer' 30 if url_model_name==model_name: #防止其他表通过权限 31 if request.user.id: #如果有ID 32 list= request.user.customer_set.all()#获取ID 的客户表 33 list_id=[] 34 for obtain in list:#循环客户表ID 35 results=obtain.id 36 list_id.append(results)#生成列表 37 if url_parameter in list_id: #对比URL参数 在不在 客户表ID里 38 return True 39 else: 40 return False 41 else: 42 return False 43 44 # ————————75PerfectCRM实现CRM扩展权限————————
如果感觉本章博客对您有帮助,请尽情打赏吧!
您的资助是我最大的动力!
金额随意,欢迎来赏!
如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的
因为,我的写作热情也离不开您的肯定支持,感谢您的阅读,我是【颜言】!