1.模型类的创建
from django.db import models # 使用django内置的用户表 from django.contrib.auth.models import User class UserProfile(models.Model): """ 用户信息表 """ user = models.OneToOneField(User) # 创建外键,关联django用户表 # 扩展用户字段 name = models.CharField(max_length=32, verbose_name="姓名") role = models.ManyToManyField("Role", blank=True) # 双向一对多==多对多 def __str__(self): return self.name class Role(models.Model): """ 角色表 """ name = models.CharField(max_length=32, unique=True) # 角色名不可以重复 menus = models.ManyToManyField("Menus",blank=True) def __str__(self): return self.name class CustomerInfo(models.Model): """ 客户信息 """ name = models.CharField(max_length=32, default=None) # 首次报名可能不知道名字 source_choices = ( (0, ‘QQ群‘), (1, ‘51CTO‘), (2, ‘百度推广‘), (3, ‘知乎‘), (4, ‘转介绍‘), (5, ‘其它‘) ) source = models.SmallIntegerField(choices=source_choices) referral_from = models.ForeignKey("self",blank=True,null=True,verbose_name="转介绍") # 关联自己 contact_type_choices = ( (0, ‘qq‘), (1, ‘微信‘), (2, ‘手机‘), ) contact_type = models.SmallIntegerField(choices=contact_type_choices) contact = models.CharField(max_length=64, unique=True) consult_courses = models.ManyToManyField("Course", verbose_name="咨询课程") consult_content = models.TextField(verbose_name="咨询内容") consultant = models.ForeignKey("UserProfile",verbose_name="课程顾问") status_choices = ( (0, ‘未报名‘), (1, ‘已报名‘), (2, ‘已退学‘), ) status = models.SmallIntegerField(choices=status_choices) date = models.DateField(auto_now_add=True) def __str__(self): return self.name class CustomerFollowUp(models.Model): """ 客户跟踪记录表 """ customer = models.ForeignKey(‘CustomerInfo‘) content = models.TextField(verbose_name="跟踪内容") user = models.ForeignKey(‘UserProfile‘, verbose_name="跟进人") date = models.DateTimeField(auto_now_add=True) status_choices = ( (0, ‘近期无报名计划‘), (1, ‘一个月内报名‘), (2, ‘2周内报名‘), (3, ‘已报名‘), ) status = models.SmallIntegerField(choices=status_choices,verbose_name="跟进状态") def __str__(self): return self.content class Course(models.Model): """ 课程 """ name = models.CharField(verbose_name="课程名", unique=True, max_length=64) price = models.PositiveSmallIntegerField() outline = models.TextField(verbose_name="课程大纲") period = models.PositiveSmallIntegerField(verbose_name="课程周期(月)", default=5) def __str__(self): return self.name class ClassList(models.Model): """ 班级列表 """ branch = models.ForeignKey(‘Branch‘) # 关联校区 course = models.ForeignKey("Course") class_type_choices = ((0,‘脱产‘),(1,‘周末‘),(2,‘网络班‘)) class_type = models.SmallIntegerField(choices=class_type_choices,default=0) semester = models.SmallIntegerField(verbose_name="学期") teachers = models.ManyToManyField(‘UserProfile‘, verbose_name="讲师") start_date = models.DateField(verbose_name="开班日期") graduate_date = models.DateField("毕业日期", blank=True, null=True) def __str__(self): return "{0}({1})期".format(self.course.name,self.semester) class Meta: """联合唯一""" unique_together = (‘branch‘,‘course‘, ‘semester‘) class CourseRecord(models.Model): """ 上课记录 """ class_grade = models.ForeignKey("ClassList", verbose_name="上课班级") day_num = models.PositiveSmallIntegerField(verbose_name="课程节次") teacher = models.ForeignKey("UserProfile", verbose_name="本节讲师") title = models.CharField("本节主题", max_length=64) content = models.TextField("本节内容") has_homework = models.BooleanField("本节有作业", default=True) homework = models.TextField("作业需求", blank=True, null=True) date = models.DateTimeField(auto_now_add=True) def __str__(self): return "{0}第{1}节".format(self.class_grade,self.day_num) class Meta: unique_together = (‘class_grade‘, ‘day_num‘) class StudyRecord(models.Model): """ 学习记录 """ course_record = models.ForeignKey(CourseRecord) student = models.ForeignKey("Student") score_choices = ( (100, "A+"), (90, "A"), (85, "B+"), (80, "B"), (75, "B-"), (70, "C+"), (60, "C"), (40, "C-"), (-50, "D"), (0, "N/A"), ) score = models.SmallIntegerField(choices=score_choices) show_choices = ( (0, "缺勤"), (1, "已签到"), (2, "迟到"), (3, "早退"), ) show_status = models.SmallIntegerField(choices=show_choices,default=1) note = models.TextField("成绩备注", blank=True, null=True) date = models.DateTimeField(auto_now_add=True) def __str__(self): return "{0} {1} {2}".format(self.course_record,self.student,self.score) class Student(models.Model): """ 学员表 """ customer = models.ForeignKey("CustomerInfo") class_grade = models.ManyToManyField("ClassList") def __str__(self): return self.customer class Branch(models.Model): """ 校区 """ name = models.CharField(max_length=32, unique=True) addr = models.CharField(max_length=128, blank=True, null=True) def __str__(self): return self.name class Menus(models.Model): """动态菜单""" name = models.CharField(max_length=64) url_type_choices = ( (0, ‘absolute‘), (1, ‘dynamic‘) ) url_type = models.SmallIntegerField(choices=url_type_choices, default=0) url_name = models.CharField(max_length=128) def __str__(self): return self.name class Meta: unique_together = (‘name‘, ‘url_name‘)
2.类似djang-admin功能的页面开发之左侧菜单栏 | 登录
# base.html存放公共的静态文件; # index.html存放整体布局; # 继承 {% extends ‘base.html‘ %} # PerfectCRM/urls.py ... url(r‘crm/‘, include(‘crm.urls‘)) # crm/urls.py ... url(r‘^$‘, views.dashboard) # crm/views.py def dashboard(request): return render(request, ‘crm/dashboard.html‘) # template-crm-dashboard.html|继承index.html # - # 配置显示静态文件 # 将base.html中body部分放入index.html # 去掉search,Dashboard,Settings,Profile # 在help位置显示用户登录状态; # Dashboard下所有标签以及左侧菜单ul标签内容都删除; # 左侧菜单显示当前登录角色的表; # 不同角色,拥有几乎完全不同的页面,但是共同点是都需要一个动态的菜单栏; # 用一个表分别记录菜单栏上的名字以及对应的url并且与角色关联; # url可能涉及(\d+)等参数,所以分成动态url与静态url供用户选择 class Menus(models.Model): """动态菜单""" name = models.CharField(max_length=64) url_type_choices = ( (0, ‘absolute‘), (1, ‘dynamic‘) ) url_type = models.SmallIntegerField(chioces=url_type_choicesm,default=0) url_name = models.CharField(max_length=128) def __str__(self): return self.name class Meta: unique_together = (‘name‘,‘url_name‘) # 角色与菜单多对多关系,在Role表中添加关联 class Role(models.Model): ... menus = models.ManyToManyField("Menus",blank=True) # 迁移 # 在后台管理系统中添加Menus Name:首页 Url type:dynamic Url name:sales_dashboard # 意味着urls.py中name=‘sales_dashboard‘ Name:客户库 Url type:absolute Url name:/crm/customers Name:我的课程 Url type:absolute Url name:/student/my_courses # 在后台管理系统中添加Roles Names:sales Menus:首页,客户库 Names:students Menus:我的课程 # 创建用户关联UserProfile User:python 姓名:miaokela Role:sales User:python 姓名:mic Role:students # 这里出现了一个问题,两个用户共用了django的一个账户; # 所以需要将与django自带的user表改成一对一关联 User:python 姓名:miaokela Role:sales User:Lily 姓名:赵丽颖 Role:students # ==============>>>> 测试不通过角色登录之后显示的动态菜单; # --->> 用django自带的auth写一个用户登录; # 在bootstrap上找一个登录页面; # 拷贝框,以及signin.css,载入到base.html # 新建一个登录页面login.html {% extends ‘index.html‘ %} {% block body %} <div class="container"> <!-- action不写,默认为当前页 --> <form class="form-signin" method="post"> {% csrf_token %} <h2 class="form-signin-heading">PerfectCRM</h2> <label for="inputEmail" class="sr-only">Username</label> <input type="email" id="inputEmail" name=‘username‘ class="form-control" placeholder="Username" required autofocus> <label for="inputPassword" class="sr-only">Password</label> <input type="password" id="inputPassword" name=‘password‘ class="form-control" placeholder="Password" required> <div class="checkbox"> <label> <input type="checkbox" value="remember-me"> Remember me </label> </div> <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button> </form> </div> {% endblock body %} # 写一个登录的views以及urls(写在项目全局中) # views.py def user_login(request): return render(request, ‘login.html‘) # urls.py ... url(r‘^login/‘,views.login) # 完善login.html里的table,action不填表示当前页面 # 后端收到POST提交数据 # views.py def user_login(request): if request.method == "POST": username = request.POST.get("username") password = request.POST.get("password") print(username,password) return render(reqyest, ‘login.html‘) # 打印username,password,说明提交成功; # 登录验证 # views.py from django.shortcut import render,redirect from django.contrib.auth import authenticate def login(request): if request.method == "POST": username = request.POST.get("username") password = request.POST.get("password") user = authenticate(username=username,password=password) if user: print(‘authenticate successed‘) print(user,username,password) # 验证成功时,user返回python,不成功返回None; return redirect("/crm/") return render(reqyest, ‘login.html‘) # 将右上角Help改成{{request.user}},显示登录用户python # 现在出现一个问题,当admin账户登出之后,右上角显示AnonymousUser,游客登录; # 再到login.html页面登录,右上角显示还是匿名登录; # 为什么呢? # 其实刚才一直没有登录,只是因为自己登录了admin后台,才有的request.user的值; # views.py from django.shortcut import render,redirect from django.contrib.auth import authenticate,login def user_login(request): if request.method == "POST": username = request.POST.get("username") password = request.POST.get("password") user = authenticate(username=username,password=password) if user: # 登录 login(request,user) print(‘authenticate successed‘) print(user,username,password) # 验证成功时,user返回python,不成功返回None; return redirect("/crm/") return render(reqyest, ‘login.html‘) # 这样就登录成功了! # 如果登录失败返回错误信息.在前端显示 error_message = ‘‘ ... else: error_message = "wrong username or password!" # 注销登录|bootstrap里找一个下拉框 <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="true">{{ request.user }}<span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">个人信息</a></li> <li><a href="{% url ‘logout‘ %}">注销</a></li> </ul> </li> # 写一个登出视图以及urlconf # views.py from django.shortcut import redirect from django.contrib.auth import logout def logout(request): logout(request) return redirect(‘/login/‘) # urls.py ... url(r‘^logout/‘,views.user_logout,name=‘logout‘) # 这样就完成了登出的过程 # 但是,我们在没有登录的时候直接url输入访问页面,也可以访问? # 依然是匿名登录状态; from django.contrib.auth.decorators import login_required # 在具体的每个页面添加 @login_required def dashboard(request): return render(request, ‘crm/dashboard.html‘) # 这个时候就报错了 http://localhost:8000/accounts/login/?next=/ 这个url找不到; # 这个是django自带的跳转页面,如果没有验证成功自动跳转这个页面; # 措施: # settings.py 添加配置 # 没有登录,直接访问页面自动跳转该页面 LOGIN_URL = ‘/login/‘ # 此时访问页面跳转至: http://localhost:8000/login/?next=/ # 这段url表示,当登录之后自动跳转之前你访问的页面; # 当你login()时,它会帮你记录上次访问的页面; # 现在来解决登录成功后跳转的页面 # views.py from django.shortcut import render,redirect from django.contrib.auth import authenticate,login def user_login(request): if request.method == "POST": username = request.POST.get("username") password = request.POST.get("password") user = authenticate(username=username,password=password) if user: # 登录 login(request,user) print(‘authenticate successed‘) print(user,username,password) # 验证成功时,user返回python,不成功返回None; return redirect("/crm/") # 跳转至上次访问页面 return render(reqyest, ‘login.html‘) # 登录成功之后要访问的是next参数指定的页面; # 如果没有next的值,就跳转至首页; return redirect(request.GET.get(‘next‘,‘/‘))