Django项目:CRM(客户关系管理系统)--71--61PerfectCRM实现CRM学生上传作业
1 # student_urls.py 2 # ————————60PerfectCRM实现CRM学生上课记录———————— 3 from django.conf.urls import url 4 from bpm.student import student_views 5 6 urlpatterns = [ 7 url(r'^student_course/$', student_views.student_course, name='student_course'), #学生报名的课程 8 url(r'^studyrecords/(\d+)/$', student_views.studyrecords, name='studyrecords'), # #学生上课记录列表StudyRecord 9 10 # ————————61PerfectCRM实现CRM学生上传作业———————— 11 url( r'^homework_detail/(\d+)/(\d+)/$', student_views.homework_detail, name='homework_detail' ), # 作业详情 12 # ————————61PerfectCRM实现CRM学生上传作业———————— 13 ] 14 # ————————60PerfectCRM实现CRM学生上课记录————————
1 # student_views.py 2 # ————————60PerfectCRM实现CRM学生上课记录———————— 3 from django.shortcuts import render #页面返回 4 from crm import models #数据库 5 from django.contrib.auth.decorators import login_required # 登陆后页面才能访问 6 #学生报名的课程 7 @login_required # 登陆后页面才能访问 8 def student_course(request): 9 enrollmentlist=request.user.stu_account.enrollment_set.all()#根据账号表关联的ID获取06学员报名信息表 10 return render(request, 'bpm_student/student_course.html', locals()) 11 12 #学生上课记录列表 13 @login_required # 登陆后页面才能访问 14 def studyrecords(request,enroll_obj_id): 15 enroll_obj=models.Enrollment.objects.get(id=enroll_obj_id)#根据ID获取06学员报名信息表 16 studyrecordlist=enroll_obj.studyrecord_set.all()#根据06学员报名信息表的ID获取09学习纪录 17 return render(request,'bpm_student/studyrecords.html',locals()) 18 19 # ————————60PerfectCRM实现CRM学生上课记录———————— 20 21 # ————————61PerfectCRM实现CRM学生上传作业———————— 22 from django.contrib.auth.decorators import login_required #登陆才能访问 23 from PerfectCRM import settings #静态配置文件 #作业上传 # 上传路径 24 import os,json,time #系统操作 25 from django.shortcuts import HttpResponse #页面返回 26 from django.shortcuts import redirect #页面返回 27 #作业详情 28 @login_required#登陆才能访问 29 def homework_detail(request,enroll_obj_id,studyrecord_id): 30 studyrecord_obj=models.StudyRecord.objects.get(id=studyrecord_id)#取学习记录 对象 31 enroll_obj=models.Enrollment.objects.get(id=enroll_obj_id)#取班级对象 32 33 # 作业根目录 班级ID 上课记录ID 学习记录ID 34 homework_path="{base_dir}/{class_id}/{course_record_id}/{studyercord_id}/".format( 35 base_dir=settings.HOMEWORK_DATA, #静态配置文件 36 class_id=studyrecord_obj.student.enrolled_class_id,#09学习纪录#学生名字#所报班级ID号 37 course_record_id=studyrecord_obj.course_record_id,#09学习纪录#每节课上课纪录表 38 studyercord_id=studyrecord_obj.id##09学习纪录 39 ) 40 print('homework_path路径:',studyrecord_obj.student.enrolled_class_id,studyrecord_obj.course_record_id,studyrecord_obj.id) 41 42 if os.path.exists(homework_path):#判断目录是否存在 43 file_lists = [] # 已经上传的文件列表 44 for file_name in os.listdir( homework_path ): 45 f_path = '%s/%s' % (homework_path, file_name) # 文件名字 46 modify_time = time.strftime( "%Y-%m-%d %H:%M:%S", time.gmtime( os.stat( f_path ).st_mtime ) ) # 文件上传时间 47 file_lists.append( [file_name, os.stat( f_path ).st_size, modify_time] ) # 添加到文件列表#文件名字#文件大小文件上传时间 48 49 50 if request.method=="POST":#上传 51 ret=False 52 data=request.POST.get('data') #ajax 53 if data:#如果有删除动作 54 del_f_path="%s/%s"%(homework_path,data)#文件路径 55 print('删除文件,路径:',del_f_path) 56 os.remove(del_f_path) #删除 57 ret=True 58 return HttpResponse(json.dumps(ret))#ret=False 59 if request.is_ajax(): # ajax上传图片 #异步提交 60 print("POST",request.POST) 61 if not os.path.isdir( homework_path ): # 没有目录 #isdir返回true,如果路径名是指现有的目录。 62 os.makedirs( homework_path, exist_ok=True ) # 创建目录 63 for k,v in request.FILES.items():#上传的文件 64 with open('%s/%s'%(homework_path,v.name),'wb') as f:#chunk 写入文件 65 for chunk in v.chunks(): #循环写文件 66 f.write(chunk) 67 return HttpResponse( json.dumps( {"status": 0, 'mag': "上传完成!", 'file_lists': file_lists} ) ) # 上传文件返回 68 69 if request.method=="POST":#上传 70 link = request.POST.get( 'link' ) # 让页面POST提交的值,在页面GET后仍然存在显示 71 if link: 72 homework_link=models.StudyRecord.objects.filter( id=studyrecord_id ).update(homework_link=link) 73 return redirect('/bpm/homework_detail/%s/%s/' %(enroll_obj_id,studyrecord_id) )#跳转到enrollment_rejection 74 return render(request,'bpm_student/homework_detail.html',locals()) 75 # ————————61PerfectCRM实现CRM学生上传作业————————
1 # settings.py 2 3 """ 4 Django settings for PerfectCRM project. 5 6 Generated by 'django-admin startproject' using Django 2.0.3. 7 8 For more information on this file, see 9 https://docs.djangoproject.com/en/2.0/topics/settings/ 10 11 For the full list of settings and their values, see 12 https://docs.djangoproject.com/en/2.0/ref/settings/ 13 """ 14 15 import os 16 17 # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 18 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 19 20 21 # Quick-start development settings - unsuitable for production 22 # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ 23 24 # SECURITY WARNING: keep the secret key used in production secret! 25 SECRET_KEY = 'atkhzsd7emv4_okn@ynhji)p)qbpuvhq+a7@yx5=chaa0$l_br' 26 27 # SECURITY WARNING: don't run with debug turned on in production! 28 DEBUG = True 29 30 ALLOWED_HOSTS = [] 31 32 33 # Application definition 34 35 INSTALLED_APPS = [ 36 'django.contrib.admin', 37 'django.contrib.auth', 38 'django.contrib.contenttypes', 39 'django.contrib.sessions', 40 'django.contrib.messages', 41 'django.contrib.staticfiles', 42 43 # ————————04PerfectCRM实现King_admin注册功能———————— 44 # 'crm.apps.CrmConfig', 45 'crm', 46 # ————————04PerfectCRM实现King_admin注册功能———————— 47 48 # ————————02PerfectCRM创建ADMIN页面———————— 49 'king_admin', 50 # ————————02PerfectCRM创建ADMIN页面———————— 51 # ————————38PerfectCRM实现全局账号登录注销———————— 52 'gbacc', 53 # ————————38PerfectCRM实现全局账号登录注销———————— 54 55 # ————————48PerfectCRM实现CRM客户报名流程学生合同———————— 56 'bpm', 57 # ————————48PerfectCRM实现CRM客户报名流程学生合同———————— 58 59 ] 60 61 MIDDLEWARE = [ 62 'django.middleware.security.SecurityMiddleware', 63 'django.contrib.sessions.middleware.SessionMiddleware', 64 'django.middleware.common.CommonMiddleware', 65 'django.middleware.csrf.CsrfViewMiddleware', 66 'django.contrib.auth.middleware.AuthenticationMiddleware', 67 'django.contrib.messages.middleware.MessageMiddleware', 68 'django.middleware.clickjacking.XFrameOptionsMiddleware', 69 ] 70 71 ROOT_URLCONF = 'PerfectCRM.urls' 72 73 TEMPLATES = [ 74 { 75 'BACKEND': 'django.template.backends.django.DjangoTemplates', 76 # ————————02PerfectCRM创建ADMIN页面———————— 77 'DIRS': [os.path.join(BASE_DIR, 'templates'), 78 os.path.join(BASE_DIR, 'king_admin/king_templates'), 79 80 # ————————03PerfectCRM创建基本数据———————— 81 os.path.join(BASE_DIR, 'DBadd/DBadd_templates'), 82 # ————————03PerfectCRM创建基本数据———————— 83 # ————————38PerfectCRM实现全局账号登录注销———————— 84 os.path.join(BASE_DIR, 'gbacc/gbacc_templates'), 85 # ————————38PerfectCRM实现全局账号登录注销———————— 86 87 # ————————47PerfectCRM实现CRM客户报名流程———————— 88 os.path.join(BASE_DIR, 'bpm/bpm_templates'), ] 89 # ————————47PerfectCRM实现CRM客户报名流程———————— 90 91 , 92 # ————————02PerfectCRM创建ADMIN页面———————— 93 'APP_DIRS': True, 94 'OPTIONS': { 95 'context_processors': [ 96 'django.template.context_processors.debug', 97 'django.template.context_processors.request', 98 'django.contrib.auth.context_processors.auth', 99 'django.contrib.messages.context_processors.messages', 100 ], 101 }, 102 }, 103 ] 104 105 WSGI_APPLICATION = 'PerfectCRM.wsgi.application' 106 107 108 # Database 109 # https://docs.djangoproject.com/en/2.0/ref/settings/#databases 110 111 DATABASES = { 112 'default': { 113 'ENGINE': 'django.db.backends.sqlite3', 114 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 115 } 116 } 117 118 119 # Password validation 120 # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators 121 122 AUTH_PASSWORD_VALIDATORS = [ 123 { 124 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 125 }, 126 { 127 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 128 }, 129 { 130 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 131 }, 132 { 133 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 134 }, 135 ] 136 137 138 # Internationalization 139 # https://docs.djangoproject.com/en/2.0/topics/i18n/ 140 141 # ————————01PerfectCRM基本配置ADMIN———————— 142 #LANGUAGE_CODE = 'en-us' 143 144 #英文转中文方法 145 LANGUAGE_CODE = 'zh-Hans' 146 # ————————01PerfectCRM基本配置ADMIN———————— 147 148 TIME_ZONE = 'UTC' 149 150 USE_I18N = True 151 152 USE_L10N = True 153 154 USE_TZ = True 155 156 157 # Static files (CSS, JavaScript, Images) 158 # https://docs.djangoproject.com/en/2.0/howto/static-files/ 159 160 STATIC_URL = '/static/' 161 162 # ————————01PerfectCRM基本配置ADMIN———————— 163 STATICFILES_DIRS = [os.path.join(BASE_DIR,'king_admin/static'), 164 # ————————01PerfectCRM基本配置ADMIN———————— 165 # ————————38PerfectCRM实现全局账号登录注销———————— 166 os.path.join(BASE_DIR, 'gbacc/static'), 167 # ————————38PerfectCRM实现全局账号登录注销———————— 168 169 # ————————47PerfectCRM实现CRM客户报名流程———————— 170 os.path.join(BASE_DIR, 'bpm/static'),] 171 # ————————47PerfectCRM实现CRM客户报名流程———————— 172 173 174 # ————————34PerfectCRM实现CRM自定义用户———————— 175 AUTH_USER_MODEL = 'crm.UserProfile'#使用自定的admin 表单 176 # ————————34PerfectCRM实现CRM自定义用户———————— 177 178 179 180 # ————————44PerfectCRM实现账号快速注册登陆———————— 181 # send e-mail 182 EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' #email后端 183 EMAIL_USE_TLS = False #是否使用TLS安全传输协议 184 EMAIL_USE_SSL = True #是否使用SSL加密,qq企业邮箱要求使用 185 EMAIL_HOST = 'smtp.sina.cn' #发送邮件的邮箱 的 SMTP服务器 #根据情况重新配置 186 EMAIL_PORT = 465 #发件箱的SMTP服务器端口 #一般不需要修改465 187 EMAIL_HOST_USER = 'perfectcrm@sina.cn' #发送邮件的邮箱账号 #根据情况重新配置 #perfectcrm@sina.cn pydjango@sina.cn 188 EMAIL_HOST_PASSWORD = 'admin123456' #发送邮件的邮箱密码 #根据情况重新配置 189 190 # ————————44PerfectCRM实现账号快速注册登陆———————— 191 192 193 # ————————46PerfectCRM实现登陆后页面才能访问———————— 194 LOGIN_URL = '/gbacc/gbacc_login/'# login_url 配置 #默认 /accounts/login/ #注意: / (绝对路径) 195 # ————————46PerfectCRM实现登陆后页面才能访问———————— 196 197 # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片———————— 198 ENROLLED_DATA='%s/bpm/static/enrolled_data'%BASE_DIR#证件上传 # 上传路径 199 # ————————51PerfectCRM实现CRM客户报名流程学生合同上传照片———————— 200 201 202 # ————————61PerfectCRM实现CRM学生上传作业———————— 203 HOMEWORK_DATA='%s/bpm/static/homeworks'%BASE_DIR #作业上传 # 上传路径 204 # ————————61PerfectCRM实现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 # ————————61PerfectCRM实现CRM学生上传作业———————— 265 homework_link = models.TextField(blank=True,null=True)#作业链接 #TextField无限制长度的文本#Django可空#数据库可以为空 266 # ————————61PerfectCRM实现CRM学生上传作业———————— 267 268 score_choices = (#学习成绩 269 (100,"A+"), 270 (90,"A"), 271 (85,"B+"), 272 (80,"B"), 273 (75,"B-"), 274 (70,"C+"), 275 (65,"C"), 276 (40,"C-"), 277 (-20,"D"), 278 (-50,"COPY"), 279 (0,"N/A"),) 280 #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作 281 score = models.SmallIntegerField(choices=score_choices) #学习成绩 282 283 284 memo = models.TextField(blank=True,null=True)#TextField无限制长度的文本#Django可空#数据库可以为空 285 286 # DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读) 287 date = models.DateField(auto_now_add=True)#创建时间(数据库自增) 288 289 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 290 return "%s %s %s" % (self.student, self.course_record, self.score)#返回#格式化字符串#学生名字#开课记录#学习成绩 291 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据 292 unique_together = ('student','course_record')#联合索引#学生名字#开课记录 293 verbose_name_plural = "09学习纪录"#verbose_name_plural给你的模型类起一个更可读的名字 294 295 # ————————34PerfectCRM实现CRM自定义用户———————— 296 # """10账号表""" 297 # class UserProfile(models.Model): 298 # from django.contrib.auth.models import User # 使用django内置的用户表 299 # 300 # #OneToOneField一对一 #User是django Admin里的账号表#CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。 301 # user = models.OneToOneField(User,on_delete=models.CASCADE)# 用户名 #创建外键,关联django用户表 302 # 303 # name = models.CharField(max_length=32) #账号名(扩展用户字段)#CharField定长文本 304 # 305 # #ManyToManyField多对多和外键工作方式相同,只不过我们处理的是QuerySet而不是模型实例。#Django可空 306 # roles = models.ManyToManyField("Role",blank=True) #角色(权限) # 双向一对多==多对多 307 # 308 # def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 309 # return self.name #返回 #账号名 310 # class Meta: #通过一个内嵌类 "class Meta" 给你的 model 定义元数据 311 # verbose_name_plural = "10账号表"#verbose_name_plural给你的模型类起一个更可读的名字 312 # ————————34PerfectCRM实现CRM自定义用户———————— 313 314 # ————————34PerfectCRM实现CRM自定义用户———————— 315 #10账号表,创建用户和超级用户 316 from django.contrib.auth.models import BaseUserManager 317 class UserProfileManager(BaseUserManager): 318 def create_user(self, email, name, password=None): 319 """ 320 创建并保存一个用户用给定的邮件,日期 321 出生和密码。 322 """ 323 if not email:#没有email 报错 324 raise ValueError('用户必须有一个电子邮件地址') 325 326 user = self.model( 327 email=self.normalize_email(email),#验证邮箱格式 328 name=name, 329 ) 330 user.set_password(password)#加密 331 user.is_active = True 332 user.save(using=self._db) 333 return user 334 def create_superuser(self, email, name, password): 335 """ 336 创建并保存一个超级用户具有给定邮件,日期 337 出生和密码。 338 """ 339 user = self.create_user(email, 340 password=password, 341 name=name 342 ) 343 user.is_active = True 344 user.is_superuser = True 345 user.save(using=self._db) 346 return user 347 348 """10账号表""" 349 """ 350 351 #删除数据库 352 353 #调用objects = UserProfileManager()#创建账号 #关联这个函数 354 355 #运行 Terminal 356 # 生成 数据表 357 # python manage.py makemigrations 358 # 数据表 迁移 359 # python manage.py migrate 360 Django Admin里账号密码重置方法 361 #运行 Terminal 362 python manage.py createsuperuser 363 364 Email address: admin@qq.com 365 用户名 : admin 366 Password: admin123456 367 Password (again): admin123456 368 """ 369 from django.contrib.auth.models import AbstractBaseUser 370 # ————————35PerfectCRM实现CRM重写Admin密码修改———————— 371 from django.utils.translation import ugettext_lazy as _ # 语言国际化 372 from django.utils.safestring import mark_safe 373 from django.contrib.auth.models import PermissionsMixin 374 # class UserProfile(AbstractBaseUser): 375 class UserProfile(AbstractBaseUser,PermissionsMixin): 376 # ————————35PerfectCRM实现CRM重写Admin密码修改———————— 377 email=models.EmailField( 378 verbose_name='邮箱账号', 379 max_length=255, 380 unique=True#唯一 #登陆账号 381 ) 382 name=models.CharField(max_length=32,verbose_name='用户名') 383 384 # ————————35PerfectCRM实现CRM重写Admin密码修改———————— 385 password = models.CharField(_('password'), max_length=128, help_text=mark_safe('''<a href=\"../password/\">修改密码</a>''')) 386 # ————————35PerfectCRM实现CRM重写Admin密码修改———————— 387 388 is_active = models.BooleanField(default=True,verbose_name='合法账号')#权限#合法账号 389 is_superuser = models.BooleanField(default=False,verbose_name='超级账号') #超级账号 390 objects = UserProfileManager()#创建账号 #关联这个函数 391 USERNAME_FIELD ='email'#指定做为 #登陆账号 392 REQUIRED_FIELDS = ['name']#必填字段 393 394 395 # ————————60PerfectCRM实现CRM学生上课记录———————— 396 stu_account = models.ForeignKey( "Customer", verbose_name='关联学员帐号', blank=True, null=True, on_delete=models.CASCADE, 397 help_text='报名成功后创建关联帐户' ) 398 # ————————60PerfectCRM实现CRM学生上课记录———————— 399 400 def get_full_name(self): 401 return self.email 402 def get_short_name(self): 403 #用户确认的电子邮件地址 404 return self.email 405 def __str__(self): 406 return self.name 407 def has_perm(self,perm,obj=None): 408 #指明用户是否被认为活跃的。以反选代替删除帐号。 409 #最简单的可能的答案:是的,总是 410 return True #有效 账号 411 def has_module_perms(self, app_label): 412 #指明用户是否可以登录到这个管理站点。 413 # 最简单的可能的答案:是的,总是 414 return True #职员状态 415 @property 416 def is_staff(self): 417 '''“用户的员工吗?”''' 418 #最简单的可能的答案:所有管理员都是员工 419 return self.is_superuser#是不是超级用户状态 420 # AUTH_USER_MODEL = 'crm.UserProfile'#使用自定的admin 表单 #settings.py 421 # ————————34PerfectCRM实现CRM自定义用户———————— 422 423 """11角色表""" 424 class Role(models.Model): 425 name = models.CharField(unique=True,max_length=32)#角色名#CharField定长文本#角色名不可以重复#最长度=32字节 426 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 427 return self.name#返回 #角色名 428 class Meta: #通过一个内嵌类 "class Meta" 给你的 model 定义元数据 429 verbose_name_plural = "11角色表" #verbose_name_plural给你的模型类起一个更可读的名字 430 431 """12标签表""" 432 class Tag(models.Model): 433 name = models.CharField(max_length=64,unique=True) #标签名#CharField定长文本#最长度=64字节#不可以重复 434 def __str__(self): #__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。 435 return self.name #返回 #标签名 436 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据 437 verbose_name_plural = "12标签表" #verbose_name_plural给你的模型类起一个更可读的名字 438 439 # ————————01PerfectCRM基本配置ADMIN————————
1 {#homework_detail.html#} 2 {## ————————61PerfectCRM实现CRM学生上传作业————————#} 3 {% extends 'bpm_master/bpm_sample.html' %} 4 {% block right-container-content %} {#自定义内容开始 右边页面内容#} 5 <div class="panel-default"> 6 <div class="panel-body"> 7 <h4>当前用户: {{ request.user }} | 学员名字:{{ request.user.stu_account.name }} | 8 学员QQ:{{ request.user.stu_account }}</h4> 9 <div class="row" style="margin-bottom: 20px"> 10 <ol class="breadcrumb"> 11 <li><a href="/bpm/my_course/">我的课程</a></li> 12 <li><a href="/bpm/studyrecords/{{ enroll_obj.id }}/">{{ enroll_obj.enrolled_class }}</a></li> 13 <li><a href="#">第:{{ studyrecord_obj.course_record.day_num }}节</a></li> 14 </ol> 15 </div> 16 <h4>作业标题:{{ studyrecord_obj.course_record.homework_title }}</h4> 17 <h4>作业详情: 18 <pre>{{ studyrecord_obj.course_record.homework_content }}</pre> 19 </h4> 20 <h4>老师评语: 21 <pre>{{ studyrecord_obj.memo }}</pre> 22 </h4> 23 <h4>本节成绩: {{ studyrecord_obj.score }} </h4> 24 <h4>本节作业链接: 25 <pre>{{ studyrecord_obj.homework_link }}</pre> 26 </h4> 27 <form method="post" class="form-horizontal" role="form">{% csrf_token %} 28 <input type="text" class="form-control" name="link" placeholder="作业链接"> 29 <input type="submit" class="btn btn-info" value="提交"> 30 </form> 31 32 33 <hr> 34 <h4>已经上传的文件: <a id="refresh">刷新</a></h4> 35 <div class="row"> 36 <div class="col-xs-9 col-md-6"> 37 {% for file in file_lists %} 38 <div class="right"> 39 {% for foo in file %} 40 <a>{{ foo }}</a> | 41 {% endfor %} 42 <span class="img_f hide">{{ file.0 }}</span> 43 <a class="del_img">删除</a> 44 </div> 45 <br> 46 {% endfor %} 47 </div> 48 </div> 49 <h4>请上传作业</h4> 50 <form action="{{ request.path }}" method="post" id="dropz" enctype="multipart/form-data" 51 class="form-group dropzone">{% csrf_token %} 52 <input type="hidden" name="file_id" ng-model="file_id" id="file_id"/> 53 </form> 54 <h4>课程大纲: 55 <pre>{{ studyrecord_obj.course_record.outline }}</pre> 56 </h4> 57 </div> 58 </div> 59 {% endblock %} 60 61 62 {% block js %} 63 <script> 64 //页面加载时绑定按钮点击事件 65 $("#refresh").click(function () { 66 window.location.reload();//刷新当前页面. 67 }); 68 69 $('.del_img').click(function () { 70 s = $(this); 71 texts = s.parent().children("span").text(); 72 {# alert(texts);#} 73 $.ajax({ 74 url: "{{ requset.path }}", 75 type: "post", 76 data: {"data": texts}, 77 headers: {'X-CSRFtoken': $.cookie('csrftoken')}, 78 success: function (arg) { 79 if (arg) { 80 alert('删除成功!'); 81 s.parent('div').addClass('hide'); 82 {# #添加样式#隐藏#} 83 } 84 } 85 }) 86 }); 87 88 89 Dropzone.autoDiscover = false; 90 appElement = document.querySelector('div .inmodal'); 91 myDropzone = new Dropzone("#dropz", { 92 url: "{{ request.path }}",//文件提交地址 93 paramName: "file", //默认为file 94 method: "post", //也可用put 95 addRemoveLinks: true, 96 maxFiles: 1,//一次性上传的文件数量上限 97 maxFilesize: 2, //文件大小,单位:MB 98 acceptedFiles: ".zip,.7z", //上传的类型 99 {# uploadMultiple: true,#}//上传多个 100 parallelUploads: 1,//一次上传的文件数量 101 dictDefaultMessage: '请将作业压缩打包后上传', 102 dictMaxFilesExceeded: "您最多只能上传1个文件!", 103 dictResponseError: '文件上传失败!', 104 dictInvalidFileType: "文件类型只能是*.zip,*.7z。", 105 dictFallbackMessage: "浏览器不受支持", 106 dictFileTooBig: "文件过大上传文件最大支持.", 107 dictRemoveLinks: "删除", 108 dictCancelUpload: "取消", 109 110 111 init: function () { 112 this.on("addedfile", function (file) { 113 //上传文件时触发的事件 114 document.querySelector('div .dz-default').style.display = 'none'; 115 }); 116 this.on("success", function (file, data) { 117 //上传成功触发的事件 118 console.log('ok'); 119 }); 120 this.on("error", function (file, data) { 121 //上传失败触发的事件 122 console.log('fail'); 123 var message = ''; 124 //lavarel框架有一个表单验证, 125 //对于ajax请求,JSON 响应会发送一个 422 HTTP 状态码, 126 //对应file.accepted的值是false,在这里捕捉表单验证的错误提示 127 if (file.accepted) { 128 $.each(data, function (key, val) { 129 message = message + val[0] + ';'; 130 }); 131 //控制器层面的错误提示,file.accepted = true的时候; 132 alert(message); 133 } 134 }); 135 this.on("removedfile", function (file) { 136 //删除文件时触发的方法 137 document.querySelector('div .dz-default').style.display = 'block'; 138 }); 139 } 140 }); 141 </script> 142 {% endblock %} 143 {## ————————61PerfectCRM实现CRM学生上传作业————————#}
1 {#studyrecords.html#} 2 {## ————————60PerfectCRM实现CRM学生上课记录————————#} 3 {% extends 'bpm_master/bpm_sample.html' %} 4 {% load bpm_tags %} 5 {% block right-container-content %} {#自定义内容开始 右边页面内容#} 6 <div class="panel-default"> 7 <div class="panel-body"> 8 <h4>当前用户: {{ request.user }} | 学员名字:{{ request.user.stu_account.name }} | 9 学员QQ:{{ request.user.stu_account }}</h4> 10 <ol class="breadcrumb"> 11 <li><a href="/bpm/student_course/">我的课程</a></li> 12 <li><a href="/bpm/studyrecords/{{ enroll_obj.id }}/">{{ enroll_obj.enrolled_class }}</a></li> 13 </ol> 14 15 <table class="table table-striped table-responsive "> 16 <thead> 17 <tr> 18 <th>课程节次</th> 19 <th>签到状态</th> 20 <th>本节作业</th> 21 <th>本节成绩</th> 22 <th>本节讲师</th> 23 <th>上课日期</th> 24 <th>本节大纲</th> 25 <th>作业标题</th> 26 <th>作业要求</th> 27 </tr> 28 </thead> 29 30 31 <tbody> 32 {% for studyrecord in studyrecordlist %} 33 <tr> 34 <td>{{ studyrecord.course_record.day_num }}</td> 35 {#课程节次#} 36 <td>{{ studyrecord.get_attendance_display }}</td> 37 {#签到状态#} 38 <td> 39 <a href="{% url 'homework_detail' enroll_obj.id studyrecord.id %}"> 40 {{ studyrecord.course_record.has_homework }} 41 </a> 42 </td> 43 {#本节作业#} 44 <td>{{ studyrecord.get_score_display }}</td> 45 {#本节成绩#} 46 <td>{{ studyrecord.course_record.teacher }}</td> 47 {#本节讲师#} 48 <td>{{ studyrecord.course_record.date }}</td> 49 {#上课日期#} 50 <td> 51 <pre style="width: 240px;height: 60px">{{ studyrecord.course_record.outline }}</pre> 52 {#本节大纲#} 53 </td> 54 <td> 55 <pre style="width: 240px;height: 60px">{{ studyrecord.course_record.homework_title }}</pre> 56 {#作业标题#} 57 </td> 58 <td> 59 <pre style="width: 240px;height: 60px">{{ studyrecord.course_record.homework_content }}</pre> 60 {#作业要求#} 61 </td> 62 </tr> 63 {% endfor %} 64 </tbody> 65 </table> 66 </div> 67 </div> 68 {% endblock %} 69 {## ————————60PerfectCRM实现CRM学生上课记录————————#}
如果感觉本章博客对您有帮助,请尽情打赏吧!
您的资助是我最大的动力!
金额随意,欢迎来赏!
如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的
因为,我的写作热情也离不开您的肯定支持,感谢您的阅读,我是【颜言】!