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 class_type_choices = ( #上课形式
32 (0,'面授(脱产)'),
33 (1,'面授(周末)'),
34 (2,'网络班'),)
35 #PositiveSmallIntegerField正小整数 0 ~ 32767 #choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
36 class_type = models.SmallIntegerField(choices=class_type_choices)#上课形式
37
38 #PositiveSmallIntegerField正小整数 0 ~ 32767
39 semester = models.PositiveSmallIntegerField(verbose_name="学期") #课程的第几期
40
41 #ManyToManyField多对多和外键工作方式相同,只不过我们处理的是QuerySet而不是模型实例。
42 teachers = models.ManyToManyField("UserProfile") # 老师 关联到 账号表
43
44 start_date = models.DateField(verbose_name="开班日期") #DateField 日期格式 YYYY-MM-DD #verbose_name是Admin中显示的字段名称
45
46 # DateField 日期格式 YYYY-MM-DD #verbose_name是Admin中显示的字段名称 #Django可空#数据库可以为空
47 end_date = models.DateField(verbose_name="结业日期",blank=True,null=True)
48
49 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
50 return "%s %s %s" %(self.branch,self.course,self.semester) #返回 #%s格式化输出字符串 #校区#课程# 学期
51 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
52 unique_together=('branch','course','semester') #联合索引
53 verbose_name_plural = "02班级表" #verbose_name_plural给你的模型类起一个更可读的名字
54
55 """03课程表,可以报名那些课程"""
56 class Course(models.Model):
57 name = models.CharField(max_length=64,unique=True)#课程名 #CharField作用是保存文本,定长的变量类型
58 price = models.PositiveSmallIntegerField(verbose_name="学费")#学费#PositiveSmallIntegerField正小整数 0 ~ 32767
59 period = models.PositiveSmallIntegerField(verbose_name="周期(月)") #PositiveSmallIntegerField正小整数 0 ~ 32767
60 outline = models.TextField() #课程大纲 #文本类型
61 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
62 return self.name #返回 #课程名
63 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
64 verbose_name_plural = "03课程表"#verbose_name_plural给你的模型类起一个更可读的名字
65
66 '''04客户信息表'''
67 class Customer(models.Model):
68 name = models.CharField(max_length=32,blank=True,null=True)#客户名#CharField定长文本 #名字最长32 # Django可空 #数据库可以为空
69 qq = models.CharField(max_length=64,unique=True) #QQ号#CharField定长文本 #名字最长64 #唯一,不能重复
70 qq_name = models.CharField(max_length=64,blank=True,null=True)#QQ名 #CharField定长文本 #名字最长64 # Django可空 #数据库可以为空
71 phone = models.CharField(max_length=64,blank=True,null=True)#手机号 #CharField定长文本 #名字最长64 # Django可空 #数据库可以为空
72
73 source_choices = ( #客户渠道来源 (内存生成)
74 (0,'转介绍'),
75 (1,'QQ群'),
76 (2,'官网'),
77 (3,'百度推广'),
78 (4,'51CTO'),
79 (5,'知乎'),
80 (6,'市场推广'),)
81 #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
82 source = models.SmallIntegerField(choices=source_choices)#客户渠道来源
83
84 #CharField定长文本#verbose_name是Admin中显示的字段名称#名字最长64 # Django可空 #数据库可以为空
85 referral_from = models.CharField(verbose_name="转介绍人qq",max_length=64,blank=True,null=True) #来自谁介绍的
86
87 #ForeignKey就是表与表之间的某种约定的关系#verbose_name是Admin中显示的字段名称 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
88 consult_courses = models.ForeignKey("Course",verbose_name="咨询课程", on_delete=models.CASCADE) #关联到 课程表
89
90 content= models.TextField(verbose_name="咨询详情") #TextField无限制长度的文本#verbose_name是Admin中显示的字段名称
91
92 #ManyToManyField多对多和外键工作方式相同,只不过我们处理的是QuerySet而不是模型实例。
93 tags = models.ManyToManyField("Tag",blank=True)#多对多关联到 标签表
94
95 #ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
96 consultant = models.ForeignKey("UserProfile", on_delete=models.CASCADE) #关联到 账号表
97
98 memo = models.TextField(blank=True,null=True)#备注#TextField无限制长度的文本#Django可空#数据库可以为空
99
100 #DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
101 date = models.DateTimeField(auto_now_add=True)#创建时间(数据库自增)
102
103 def __str__(self): #__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
104 return self.qq #返回 #QQ号
105
106 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
107 verbose_name_plural = "04客户表" #verbose_name_plural给你的模型类起一个更可读的名字
108
109 """05客户跟进表"""
110 class CustomerFollowUp(models.Model):
111
112 #ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
113 customer = models.ForeignKey("Customer", on_delete=models.CASCADE)#客户名 #关联到 客户信息表
114
115 content = models.TextField(verbose_name="跟进内容")#跟进的内容#TextField无限制长度的文本#verbose_name是Admin中显示的字段名称
116
117 #ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
118 consultant =models.ForeignKey("UserProfile", on_delete=models.CASCADE) #关联到 账号表
119
120 intention_choices =( #报名状态
121 (0,'2周内报名'),
122 (1,'1个月内报名'),
123 (2,'近期无报名计划'),
124 (3,'已在其它机构报名'),
125 (4,'已报名'),
126 (5,'已拉黑'),)
127 #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
128 intention=models.SmallIntegerField(choices=intention_choices) #报名状态
129
130 #DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
131 date = models.DateTimeField(auto_now_add=True)#创建时间(数据库自增)
132
133 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
134 return "<%s:%s>" %(self.customer.qq,self.intention) #返回#格式化字符串#跨表里的QQ号#报名状态
135 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
136 verbose_name_plural = "05客户跟进表"#verbose_name_plural给你的模型类起一个更可读的名字
137
138 """06学员报名信息表"""
139 class Enrollment(models.Model):
140 # ForeignKey就是表与表之间的某种约定的关系#verbose_name是Admin中显示的字段名称 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
141 customer = models.ForeignKey("Customer",on_delete=models.CASCADE)#学员名字 #关联到 客户信息表
142 enrolled_class = models.ForeignKey("ClassList",verbose_name="所报班级",on_delete=models.CASCADE)#关联到 班级表
143 consultant = models.ForeignKey("UserProfile",verbose_name="课程顾问",on_delete=models.CASCADE) #关联到 账号表
144
145 #BooleanField布尔值类型#default=False默认(True)不允许出现空字符#verbose_name是Admin中显示的字段名称
146 contract_agreed = models.BooleanField(default=False,verbose_name="学员已经同意合同")#学员看合同
147 contract_approved = models.BooleanField(default=False,verbose_name="合同已经审核") #谁审核
148
149 # DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
150 date = models.DateTimeField(auto_now_add=True)#创建时间(数据库自增)
151
152 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
153 return "%s %s" %(self.customer,self.enrolled_class)#返回#格式化字符串#学员名字#所报班级
154 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
155 unique_together = ("customer","enrolled_class")#联合索引
156 verbose_name_plural = "06学员报名信息表"#verbose_name_plural给你的模型类起一个更可读的名字
157
158 """07缴费记录表"""
159 class Payment(models.Model):
160 #ForeignKey就是表与表之间的某种约定的关系#verbose_name是Admin中显示的字段名称 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
161 customer = models.ForeignKey("Customer",on_delete=models.CASCADE)#学员名字 关联到 客户信息表
162 course = models.ForeignKey("Course",verbose_name="所报课程",on_delete=models.CASCADE)#关联到 课程表
163
164 #PositiveSmallIntegerField正小整数 0 ~ 32767 #verbose_name是Admin中显示的字段名称#默认值=500
165 amount = models.PositiveIntegerField(verbose_name="数额",default=500)#缴费数额
166
167 #ForeignKey就是表与表之间的某种约定的关系#CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
168 consultant = models.ForeignKey("UserProfile",on_delete=models.CASCADE)#缴费给谁 关联到 账号表
169
170 #DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
171 date=models.DateTimeField(auto_now_add=True)#创建时间(数据库自增)
172
173 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
174 return "%s %s" %(self.customer,self.amount)#返回#格式化字符串#学员名字#缴费数额
175 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
176 verbose_name_plural = "07缴费记录表"#verbose_name_plural给你的模型类起一个更可读的名字
177
178 """08每节课上课纪录表"""
179 class CourseRecord(models.Model):
180 # ForeignKey就是表与表之间的某种约定的关系#verbose_name是Admin中显示的字段名称 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
181 from_class = models.ForeignKey("ClassList",verbose_name="班级",on_delete=models.CASCADE) #那个班级
182
183 #PositiveSmallIntegerField正小整数 0 ~ 32767 #verbose_name是Admin中显示的字段名称
184 day_num = models.PositiveSmallIntegerField(verbose_name="第几节(天)") #第几节课
185
186 # ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
187 teacher = models.ForeignKey("UserProfile",on_delete=models.CASCADE)#老师是谁 关联到 账号表
188
189 #BooleanField布尔值类型#default=True默认(True)不允许出现空字符
190 has_homework = models.BooleanField(default=True) #有没有作业
191
192 # CharField定长文本#名字最长128#Django可空#数据库可以为空
193 homework_title = models.CharField(max_length=128,blank=True,null=True) #作业标题
194
195 #TextField无限制长度的文本#Django可空#数据库可以为空
196 homework_content = models.TextField(blank=True,null=True) #作业内容
197
198 #TextField无限制长度的文本#verbose_name是Admin中显示的字段名称
199 outline =models.TextField(verbose_name="本节课程大纲") #课程主要讲什么
200
201 # DateTimeField日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] #auto_now_add创建时间(只读)
202 date = models.DateField(auto_now_add=True)#创建时间(数据库自增)
203
204 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
205 return " %s:%s" %(self.from_class,self.day_num)#返回#格式化字符串#班级#第几节(天)
206 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
207 unique_together = ("from_class","day_num") #联合索引
208 verbose_name_plural = "08每节课上课纪录表" #verbose_name_plural给你的模型类起一个更可读的名字
209
210 """09学习纪录"""
211 class StudyRecord(models.Model):
212 # ForeignKey就是表与表之间的某种约定的关系 #CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
213 student = models.ForeignKey("Enrollment",on_delete=models.CASCADE)#学生名字 关联到 学员报名信息表
214 course_record = models.ForeignKey("CourseRecord",on_delete=models.CASCADE)#开课记录 # 关联到 每节课上课纪录表
215
216 attendance_choices = (# 本节课上课状态记录
217 (0,"已签到"),
218 (1,"迟到"),
219 (2,"缺勤"),
220 (3,"早退"),)
221 #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
222 attendance = models.SmallIntegerField(choices=attendance_choices) # 本节课上课状态记录
223
224 score_choices = (#学习成绩
225 (100,"A+"),
226 (90,"A"),
227 (85,"B+"),
228 (80,"B"),
229 (75,"B-"),
230 (70,"C+"),
231 (65,"C"),
232 (40,"C-"),
233 (-20,"D"),
234 (-50,"COPY"),
235 (0,"N/A"),)
236 #PositiveSmallIntegerField正小整数 0 ~ 32767(省空间)#choices是Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
237 score = models.SmallIntegerField(choices=score_choices) #学习成绩
238
239 memo = models.TextField(blank=True,null=True)#TextField无限制长度的文本#Django可空#数据库可以为空
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 %s" % (self.student, self.course_record, self.score)#返回#格式化字符串#学生名字#开课记录#学习成绩
246 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
247 unique_together = ('student','course_record')#联合索引#学生名字#开课记录
248 verbose_name_plural = "09学习纪录"#verbose_name_plural给你的模型类起一个更可读的名字
249
250 # ————————34PerfectCRM实现CRM自定义用户————————
251 # """10账号表"""
252 # class UserProfile(models.Model):
253 # from django.contrib.auth.models import User # 使用django内置的用户表
254 #
255 # #OneToOneField一对一 #User是django Admin里的账号表#CASCADE从父表删除或更新且自动删除或更新子表中匹配的行。
256 # user = models.OneToOneField(User,on_delete=models.CASCADE)# 用户名 #创建外键,关联django用户表
257 #
258 # name = models.CharField(max_length=32) #账号名(扩展用户字段)#CharField定长文本
259 #
260 # #ManyToManyField多对多和外键工作方式相同,只不过我们处理的是QuerySet而不是模型实例。#Django可空
261 # roles = models.ManyToManyField("Role",blank=True) #角色(权限) # 双向一对多==多对多
262 #
263 # def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
264 # return self.name #返回 #账号名
265 # class Meta: #通过一个内嵌类 "class Meta" 给你的 model 定义元数据
266 # verbose_name_plural = "10账号表"#verbose_name_plural给你的模型类起一个更可读的名字
267 # ————————34PerfectCRM实现CRM自定义用户————————
268
269 # ————————34PerfectCRM实现CRM自定义用户————————
270 #10账号表,创建用户和超级用户
271 from django.contrib.auth.models import BaseUserManager
272 class UserProfileManager(BaseUserManager):
273 def create_user(self, email, name, password=None):
274 """
275 创建并保存一个用户用给定的邮件,日期
276 出生和密码。
277 """
278 if not email:#没有email 报错
279 raise ValueError('用户必须有一个电子邮件地址')
280
281 user = self.model(
282 email=self.normalize_email(email),#验证邮箱格式
283 name=name,
284 )
285 user.set_password(password)#加密
286 user.is_active = True
287 user.save(using=self._db)
288 return user
289 def create_superuser(self, email, name, password):
290 """
291 创建并保存一个超级用户具有给定邮件,日期
292 出生和密码。
293 """
294 user = self.create_user(email,
295 password=password,
296 name=name
297 )
298 user.is_active = True
299 user.is_superuser = True
300 user.save(using=self._db)
301 return user
302
303 """10账号表"""
304 """
305
306 #删除数据库
307
308 #调用objects = UserProfileManager()#创建账号 #关联这个函数
309
310 #运行 Terminal
311 # 生成 数据表
312 # python manage.py makemigrations
313 # 数据表 迁移
314 # python manage.py migrate
315 Django Admin里账号密码重置方法
316 #运行 Terminal
317 python manage.py createsuperuser
318
319 Email address: admin@qq.com
320 用户名 : admin
321 Password: admin123456
322 Password (again): admin123456
323 """
324 from django.contrib.auth.models import AbstractBaseUser
325 # ————————35PerfectCRM实现CRM重写Admin密码修改————————
326 from django.utils.translation import ugettext_lazy as _ # 语言国际化
327 from django.utils.safestring import mark_safe
328 from django.contrib.auth.models import PermissionsMixin
329 # class UserProfile(AbstractBaseUser):
330 class UserProfile(AbstractBaseUser,PermissionsMixin):
331 # ————————35PerfectCRM实现CRM重写Admin密码修改————————
332 email=models.EmailField(
333 verbose_name='邮箱账号',
334 max_length=255,
335 unique=True#唯一 #登陆账号
336 )
337 name=models.CharField(max_length=32,verbose_name='用户名')
338
339 # ————————35PerfectCRM实现CRM重写Admin密码修改————————
340 password = models.CharField(_('password'), max_length=128, help_text=mark_safe('''<a href="../password/">修改密码</a>'''))
341 # ————————35PerfectCRM实现CRM重写Admin密码修改————————
342
343 is_active = models.BooleanField(default=True,verbose_name='合法账号')#权限#合法账号
344 is_superuser = models.BooleanField(default=False,verbose_name='超级账号') #超级账号
345 objects = UserProfileManager()#创建账号 #关联这个函数
346 USERNAME_FIELD ='email'#指定做为 #登陆账号
347 REQUIRED_FIELDS = ['name']#必填字段
348 def get_full_name(self):
349 return self.email
350 def get_short_name(self):
351 #用户确认的电子邮件地址
352 return self.email
353 def __str__(self):
354 return self.name
355 def has_perm(self,perm,obj=None):
356 #指明用户是否被认为活跃的。以反选代替删除帐号。
357 #最简单的可能的答案:是的,总是
358 return True #有效 账号
359 def has_module_perms(self, app_label):
360 #指明用户是否可以登录到这个管理站点。
361 # 最简单的可能的答案:是的,总是
362 return True #职员状态
363 @property
364 def is_staff(self):
365 '''“用户的员工吗?”'''
366 #最简单的可能的答案:所有管理员都是员工
367 return self.is_superuser#是不是超级用户状态
368 # AUTH_USER_MODEL = 'crm.UserProfile'#使用自定的admin 表单 #settings.py
369 # ————————34PerfectCRM实现CRM自定义用户————————
370
371 """11角色表"""
372 class Role(models.Model):
373 name = models.CharField(unique=True,max_length=32)#角色名#CharField定长文本#角色名不可以重复#最长度=32字节
374 def __str__(self):#__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
375 return self.name#返回 #角色名
376 class Meta: #通过一个内嵌类 "class Meta" 给你的 model 定义元数据
377 verbose_name_plural = "11角色表" #verbose_name_plural给你的模型类起一个更可读的名字
378
379 """12标签表"""
380 class Tag(models.Model):
381 name = models.CharField(max_length=64,unique=True) #标签名#CharField定长文本#最长度=64字节#不可以重复
382 def __str__(self): #__str__()是Python的一个“魔幻”方法,这个方法定义了当object调用str()时应该返回的值。
383 return self.name #返回 #标签名
384 class Meta:#通过一个内嵌类 "class Meta" 给你的 model 定义元数据
385 verbose_name_plural = "12标签表" #verbose_name_plural给你的模型类起一个更可读的名字
386
387 # ————————01PerfectCRM基本配置ADMIN————————