第十九 django继续及CRM
1.创建新项目
2.设计数据库表
from django.db import models # Create your models here. from django.contrib.auth.models import User course_type_choices = (('online', '网络班'), ('offline_weekend', '面授班(周末'), ('offline_fulltime', '面授班(脱产)'), ) class School(models.Model): name = models.CharField(max_length=128,unique=True) city = models.CharField(max_length=64) addr = models.CharField(max_length=128) def __unicode__(self): return self.name class UserProfile(models.Model): User = models.OneToOneField(User) name = models.CharField(max_length=64) school = models.ForeignKey('School') def __unicode__(self): return self.name class Customer(models.Model): qq = models.CharField(max_length=64,unique=True) name = models.CharField(max_length=32,blank=True,null=True) phone = models.BigIntegerField(blank=True,null=True) course = models.ForeignKey('Course') course_type = models.CharField(max_length=64,choices=course_type_choices,default='offline_weekend') consult_memo = models.TextField() source_type_choices = (('qq','qq群'), ('referral','内部转介绍'), ('agent',''), ('others','其它'), ) source_type = models.CharField(max_length=64,choices=source_type_choices,default='qq') referral_from = models.ForeignKey('self',blank=True,null=True) status_choices = (('signed','已报名'), ('unregistered','未报名'), ('graduated','已毕业'), ('drop-off','退学'), ) status = models.CharField(max_length=64,choices=status_choices,default='signed') consultant = models.ForeignKey('UserProfile') class_list = models.ManyToManyField('ClassList',blank=True) date = models.DateField('咨询日期',auto_now_add=True) def __unicode__(self): return "%s (%s)" %(self.qq,self.name) class CustomerTrackRecord(models.Model): customer = models.ForeignKey(Customer) track_record = models.TextField('跟踪记录') track_date = models.DateField() follower = models.ForeignKey(UserProfile) status_choices = ((1,'近期无报名计划'), (2,'2个月内报名计划'), (3,'1个月内报名计划'), (4,'2周内报名计划'), (5,'1周内报名计划'), (6,'2天内报名'), (7,'已报名'), ) status = models.IntegerField('状态',choices=status_choices,help_text='选择此客户的原因') def __unicode__(self): return self.customer class Course(models.Model): name = models.CharField(max_length=64,unique=True) online_price = models.IntegerField() offline_price = models.IntegerField() introduction = models.TextField() def __unicode__(self): return self.name class ClassList(models.Model): course = models.ForeignKey(Course,verbose_name='课程') semester = models.IntegerField(verbose_name='学期') course_type = models.CharField(max_length=64, choices=course_type_choices, default='offline_weekend') teachers = models.ManyToManyField(UserProfile) start_date = models.DateField() graduate_date = models.DateField() def __unicode__(self): return "%s(%s) %s" %(self.course.name,self.course_type,self.semester) class Meta: unique_together = ('course','semester','course_type') class CourseRecord(models.Model): class_obj = models.ForeignKey(ClassList) day_num = models.IntegerField("第几节课") course_date = models.DateField(auto_now_add=True,verbose_name='上课时间') teacher = models.ForeignKey(UserProfile) def __unicode__(self): return self.class_obj,self.day_num class Meta: unique_together = ('class_obj','day_num') class StudyRecord(models.Model): course_record = models.ForeignKey(CourseRecord) student = models.ForeignKey(Customer) record_choices = (('checked','已签到'), ('late','迟到'), ('noshow','缺勤'), ('leave_early','早退') ) record = models.CharField("状态",choices=record_choices,max_length=64) score_choices = ((100,'A+'), (90,'A'), (80,'A-'), (70,'B+'), (60,'B'), (50,'C'), (40,'C-'), (0,'D'), (-1,'N/A'), (-100,'COPY'), (-1000,'FAIL') ) score = models.IntegerField("本节成绩",choices=score_choices,default=-1) date = models.DateTimeField(auto_now_add=True) note = models.CharField('备注',max_length=255,blank=True,null=True) def __unicode__(self): return "%s %s %s" %(self.course_record,self.student,self.record)
3.生成表
3.1.配置引入mysql
import pymysql pymysql.install_as_MySQLdb()
3.2.配置数据库连接文件
.... INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'cklcrm.apps.CklcrmConfig', ] .... DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), # } 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'cklcrm', 'HOST': '192.168.1.80', 'PORT': '', 'USER': 'sayyou', 'PASSWORD': 'what@F893', } } ....
3.3.生成表
4.创建admin
4.1.admin创建登录用户
4.2.注册表到admin
from django.contrib import admin import cklcrm.models # Register your models here. admin.site.register(cklcrm.models.UserProfile) admin.site.register(cklcrm.models.Customer) admin.site.register(cklcrm.models.CustomerTrackRecord) admin.site.register(cklcrm.models.ClassList) admin.site.register(cklcrm.models.Course) admin.site.register(cklcrm.models.CourseRecord) admin.site.register(cklcrm.models.StudyRecord) admin.site.register(cklcrm.models.School)
4.3.启动服务
4.4.登录admin
5.配置静态资源
5.1.添加静态目录
5.2.添加bootstrap资源
这里是bootstrap-3.3.7
5.3.保存框架页面
https://v3.bootcss.com/examples/dashboard/
加入到templates里,重命名为base并作为基准页面。
6.配置项目访问
6.1.配置全局访问url
"""s19crm URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.11/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^cklcrm/',include('cklcrm.urls')) ]
6.2.配置cklcrm url
from django.conf.urls import url,include from django.contrib import admin from cklcrm import views urlpatterns = [ url(r'^$',views.dashboard), ]
6.3.配置views里的方法
from django.shortcuts import render # Create your views here. def dashboard(request): return render(request,'cklcrm/dashboard.html')
6.4.配置dashboard.html
文件内容继承base
{% extends 'base.html' %}
6.5.配置静态文件的路径
STATIC_URL = '/static/' #别名 STATICFILES_DIRS = [ os.path.join(BASE_DIR, "statics"), #实际路径 # '/var/www/static/', ]
6.6.启动服务,访问页面
6.7.页面静态文件路径必须修改
诸如此类的路径,必须修改为别名
查看修改后页面
7.精简基页,引用基本页
7.1.精简基本页
7.2.修改基本base.html引用block
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <h1 class="page-header">{% block page-header %}You page{% endblock %}</h1> {% block page-content %} Your page haha {% endblock %} </div>
7.3.修改dashboard.html
{% extends 'base.html' %} {% block page-header %} CKL dashboard {% endblock %}
查看页面:
8.添加客户管理信息表
8.1.新增views方法
from django.shortcuts import render from cklcrm import models # Create your views here. def dashboard(request): return render(request,'cklcrm/dashboard.html') def customers(request): customers_list = models.Customer.objects.all() return render(request,'cklcrm/customers.html',{'customers_list':customers_list})
8.2.新增返回页面
{% extends 'base.html' %} {% block page-header %} 客户管理信息列表 {% endblock %} {% block page-content %} {{ customers_list }} {% endblock %}
8.4.查看返回页面
8.5.新增数据
8.5.1.新增课程
8.5.2.新增讲师
8.5.3.新增客户
8.5.4.查看页面
9.添加表格展示
9.1.修改返回customer.html
{% extends 'base.html' %} {% block page-header %} 客户管理信息列表 {% endblock %} {% block page-content %} {{ customers_list }} <table class="table table-hover"> <thead> <tr> <th>ID</th> <th>QQ</th> <th>姓名</th> <th>渠道</th> <th>咨询课程</th> <th>课程类型</th> <th>客户备注</th> <th>状态</th> <th>课程顾问</th> <th>日期</th> </tr> </thead> <tbody> {% for customer in customers_list %} <tr> <td>{{ customer.id }}</td> <td>{{ customer.qq }}</td> <td>{{ customer.name }}</td> <td>{{ customer.source_type }}</td> <td>{{ customer.course }}</td> <td>{{ customer.course_type }}</td> <td>{{ customer.consult_memo }}</td> <td>{{ customer.status }}</td> <td>{{ customer.consultant }}</td> <td>{{ customer.date }}</td> </tr> {% endfor %} </tbody> </table> {% endblock %}
查看结果:
9.2.字段名称显示中文
修改html
<tr> <td>{{ customer.id }}</td> <td>{{ customer.qq }}</td> <td>{{ customer.name }}</td> <td>{{ customer.source_type }}</td> <td>{{ customer.course }}</td> <td>{{ customer.get_course_type_display }}</td> <td>{{ customer.consult_memo }}</td> <td>{{ customer.get_status_display }}</td> <td>{{ customer.consultant }}</td> <td>{{ customer.date }}</td> </tr>
查看修改结果:
10.为状态增加颜色
10.1.新增颜色css
.signed {
background-color: #4cae4c;
}
.unregistered {
background-color: #ff6f06;
}
.graduated {
background-color: #9d9d9d;
}
.drop-off {
background-color: red;
}
10.2.新增静态引用
10.3.增加显示样式
<td>{{ customer.id }}</td> <td>{{ customer.qq }}</td> <td>{{ customer.name }}</td> <td>{{ customer.source_type }}</td> <td>{{ customer.course }}</td> <td>{{ customer.get_course_type_display }}</td> <td>{{ customer.consult_memo|truncatewords:10 }}</td> <td class="{{ customer.status }}">{{ customer.get_status_display }}</td> <td>{{ customer.consultant }}</td> <td>{{ customer.date }}</td>
查看结果:
11.分页
11.1.django分页模块
https://docs.djangoproject.com/en/2.0/topics/pagination/
11.2.新增数据
11.3.配置分页
11.3.1.配置后端返回
from django.shortcuts import render from cklcrm import models # Create your views here. from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger def dashboard(request): return render(request,'cklcrm/dashboard.html') def customers(request): customers_list = models.Customer.objects.all()
#返回每页显示的条数 paginator = Paginator(customers_list,3) page = request.GET.get('page') try: customer_pages = paginator.page(page) except PageNotAnInteger:
#如果输入的页数不存在,默认返回第一页 customer_pages = paginator.page(1) except EmptyPage:
#如果页数超出,则返回最后一页 customer_pages = paginator.page(paginator.num_pages) # return render(request,'cklcrm/customers.html',{'customers_list':customers_list}) return render(request, 'cklcrm/customers.html', {'customers_list': customer_pages})
11.3.2.配置前端返回
在表格下面新增如下:
<div class="pagination"> <span class="step-links"> {% if customers_list.has_previous %} <a href="?page=1">« first</a> <a href="?page={{ customers_list.previous_page_number }}">previous</a> {% endif %} <span class="current"> Page {{ customers_list.number }} of {{ customers_list.paginator.num_pages }}. </span> {% if customers_list.has_next %} <a href="?page={{ customers_list.next_page_number }}">next</a> <a href="?page={{ customers_list.paginator.num_pages }}">last »</a> {% endif %} </span> </div>
11.3.查看页面
11.4.分页优化一
11.4.1.增加如下样式
https://v3.bootcss.com/components/#pagination
11.4.2.前端展示增加
<nav aria-label=""> <ul class="pagination"> <!-- 如果还有上一页,则增加想做的箭头 --> {% if customers_list.has_previous %} <li class=""><a href="?page={{ customers_list.previous_page_number }}" aria-label="Previous"><span aria-hidden="true">«</span></a></li> {% endif %} <!-- 循环页码,展示所有页码 --> {% for page_num in customers_list.paginator.page_range %} <!-- 如果循环页码等于当前页码,则增加样式 --> {% if page_num == customers_list.number %} <li class="active"><a href="?page={{ page_num }}">{{ page_num }} <span class="sr-only">(current)</span></a></li> {% else %} <li class=""><a href="?page={{ page_num }}">{{ page_num }} <span class="sr-only">(current)</span></a></li> {% endif %} {% endfor %} <!-- 如果还有下一页,则增加向右的箭头 --> {% if customers_list.has_next %} <li class=""><a href="?page={{ customers_list.next_page_number }}" aria-label="Next"><span aria-hidden="true">»</span></a></li> {% endif %} </ul> </nav>
11.4.3.查看结果
11.5.增加页码缩减
11.5.1.如果页码很多,就没办法全部显示
11.5.2.优化办法,只显示当前页的最近两三页
思路:获取当前页码号码,然后取当前页 减去 循环的页数,如果小于等于2则正确
abs(current_page - i_page )
比如当前是10
abs(10 - 8)
abs(10 - 12)
但是,没有这个方法,所以需要自定义
11.5.3.自定义返回前端页码方法
https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/
11.5.4.方法演示
11.5.4.1.新增包
#!/usr/bin/env python # -*- coding: utf-8 -*- from django import template register = template.Library() @register.filter def ckl_upper(val): print("-- from my temp:") return val.upper()
11.5.4.2.前端返回引用
前端引用自定义方法
将渠道信息转为大写:
查看结果:
11.6.自定义返回方法
11.6.1.定义自定义方法
#!/usr/bin/env python # -*- coding: utf-8 -*- from django import template from django.utils.html import format_html register = template.Library() @register.filter def ckl_upper(val): print("-- from my temp:") return val.upper() #传入多个参数使用如下 @register.simple_tag def neb_page(current_num,loop_num): #获取当前页及循环页的偏移量 offset = abs(current_num - loop_num) #如果小于3则 if offset < 3: #如果循环页等于当前页,就给页码加色 if loop_num == current_num: page_ele = '''<li class="active"><a href="?page=%s">%s<span class="sr-only">(current)</span></a></li>''' %(loop_num,loop_num) else: page_ele = '''<li class=""><a href="?page=%s">%s<span class="sr-only">(current)</span></a></li>''' % (loop_num, loop_num) return format_html(page_ele) else: return ""
11.6.2.前端返回定义
{% extends 'base.html' %} {% load custom_page %} {% block page-header %} 客户管理信息列表 {% endblock %} {% block page-content %} <table class="table table-hover"> <thead> <tr> <th>ID</th> <th>QQ</th> <th>姓名</th> <th>渠道</th> <th>咨询课程</th> <th>课程类型</th> <th>客户备注</th> <th>状态</th> <th>课程顾问</th> <th>日期</th> </tr> </thead> <tbody> {% for customer in customers_list %} <tr> <td>{{ customer.id }}</td> <td>{{ customer.qq }}</td> <td>{{ customer.name }}</td> <td>{{ customer.source_type | ckl_upper}}</td> <td>{{ customer.course }}</td> <td>{{ customer.get_course_type_display }}</td> <td>{{ customer.consult_memo|truncatechars:30 }}</td> <td class="{{ customer.status }}">{{ customer.get_status_display }}</td> <td>{{ customer.consultant }}</td> <td>{{ customer.date }}</td> </tr> {% endfor %} </tbody> </table> <nav aria-label=""> <ul class="pagination"> <!-- 如果还有上一页,则增加想做的箭头 --> {% if customers_list.has_previous %} <li class=""> <a href="?page={{ customers_list.previous_page_number }}" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% endif %} <!-- 循环页码,展示所有页码 --> {% for page_num in customers_list.paginator.page_range %} <!-- 返回自定义方法的结果 --> {% neb_page customers_list.number page_num %} {% endfor %} <!-- 如果还有下一页,则增加向右的箭头 --> {% if customers_list.has_next %} <li class=""> <a href="?page={{ customers_list.next_page_number }}" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> {% endif %} </ul> </nav> <div class="pagination"> <span class="step-links"> {% if customers_list.has_previous %} <a href="?page=1">« first</a> <a href="?page={{ customers_list.previous_page_number }}">previous</a> {% endif %} <span class="current"> Page {{ customers_list.number }} of {{ customers_list.paginator.num_pages }}. </span> {% if customers_list.has_next %} <a href="?page={{ customers_list.next_page_number }}">next</a> <a href="?page={{ customers_list.paginator.num_pages }}">last »</a> {% endif %} </span> </div> {% endblock %}
查看结果:
12.选择查看详细信息
12.1.点击id进入详细信息
12.1.1.添加a标签,点击a标签进入详细页
思路:当前页面是:http://127.0.0.1:8000/cklcrm/customers/?page=1
希望点击id,进入:http://127.0.0.1:8000/cklcrm/customers/1/ 此处是详细信息
12.1.2.增加url
from django.conf.urls import url,include from django.contrib import admin from cklcrm import views urlpatterns = [ url(r'^$',views.dashboard), url(r'^customers/$',views.customers), url(r'^customers/(\d+)/$',views.customsers_detail) ]
12.1.3.使用modelfrom
新增forms
#!/usr/bin/env python # -*- coding: utf-8 -*- from django.forms import Form,ModelForm from cklcrm import models class CustomerModelForm(ModelForm): class Meta: model = models.Customer exclude = ()
12.1.4.配置views方法
from django.shortcuts import render from cklcrm import models
#导入forms from cklcrm import forms # Create your views here. from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger def dashboard(request): return render(request,'cklcrm/dashboard.html') def customers(request): customers_list = models.Customer.objects.all() paginator = Paginator(customers_list,3) page = request.GET.get('page') try: customer_pages = paginator.page(page) except PageNotAnInteger: customer_pages = paginator.page(1) except EmptyPage: customer_pages = paginator.page(paginator.num_pages) # return render(request,'cklcrm/customers.html',{'customers_list':customers_list}) return render(request, 'cklcrm/customers.html', {'customers_list': customer_pages})
#返回forms结果 def customsers_detail(request,customer_id): customer_obj = models.Customer.objects.get(id=customer_id) form = forms.CustomerModelForm() return render(request,'cklcrm/customers_detail.html',{'customer_form':form})
12.1.5.添加静态文件
查看文件内容:
{% extends 'base.html' %} {% load custom_page %} {% block page-header %} 客户详细信息 {% endblock %} {% block page-content %} {{ customer_form }} {% endblock %}
12.1.6.点击id查看内容
内容为空:
12.1.7.列表没有内容,需要增加内容
def customsers_detail(request,customer_id): customer_obj = models.Customer.objects.get(id=customer_id) form = forms.CustomerModelForm(instance=customer_obj) return render(request,'cklcrm/customers_detail.html',{'customer_form':form})
再次查看:
12.1.8.给某个字段加样式
比如让qq这个字段
修改forms
#!/usr/bin/env python # -*- coding: utf-8 -*- from django.forms import Form,ModelForm from cklcrm import models class CustomerModelForm(ModelForm): class Meta: model = models.Customer exclude = () def __init__(self,*args,**kwargs): super(CustomerModelForm,self).__init__(*args,**kwargs) self.fields['qq'].widget.attrs["class"] = "form-control"
查看结果:
12.1.9.给所有字段加样式
修改forms
#!/usr/bin/env python # -*- coding: utf-8 -*- from django.forms import Form,ModelForm from cklcrm import models class CustomerModelForm(ModelForm): class Meta: model = models.Customer exclude = () def __init__(self,*args,**kwargs): super(CustomerModelForm,self).__init__(*args,**kwargs) #self.fields['qq'].widget.attrs["class"] = "form-control"
#循环所有字段 for filed_name in self.base_fields: filed = self.base_fields[filed_name] filed.widget.attrs.update({'class':'form-control'})
查看结果:
12.2.提交修改内容
12.2.1.页面增加样式
https://v3.bootcss.com/css/#forms
页面希望修改如下:
12.2.2.修改返回页面
{% extends 'base.html' %} {% load custom_page %} {% block page-header %} 客户详细信息 {% endblock %} {% block page-content %} <!-- 新增提交form --> <form class="form-horizontal" method="post"> <!-- 循环每个字段,增加样式 --> {% for filed in customer_form %} <div class="form-group"> <label for="inputEmail3" class="col-sm-2 control-label">{{ filed.label }}</label> <div class="col-sm-10"> {{ filed }} </div> </div> {% endfor %} <!-- 按钮样式 --> <div class="col-sm-12"> <input class="btn btn-success pull-right" type="submit" value="Save"> </div> </form> {% endblock %}
12.3.提交修改
12.3.1.修改views方法
from django.shortcuts import render,redirect from cklcrm import models from cklcrm import forms # Create your views here. from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger def dashboard(request): return render(request,'cklcrm/dashboard.html') def customers(request): customers_list = models.Customer.objects.all() paginator = Paginator(customers_list,3) page = request.GET.get('page') try: customer_pages = paginator.page(page) except PageNotAnInteger: customer_pages = paginator.page(1) except EmptyPage: customer_pages = paginator.page(paginator.num_pages) # return render(request,'cklcrm/customers.html',{'customers_list':customers_list}) return render(request, 'cklcrm/customers.html', {'customers_list': customer_pages}) def customsers_detail(request,customer_id): customer_obj = models.Customer.objects.get(id=customer_id) if request.method == "POST": #不加instance=customer_obj,就是创建一条新记录,而不是更新数据 form = forms.CustomerModelForm(request.POST,instance=customer_obj) if form.is_valid(): form.save() #获取到首页的url,并返回 base_url = "/".join(request.path.split("/")[0:-2]) return redirect(base_url) else: form = forms.CustomerModelForm(instance=customer_obj) return render(request,'cklcrm/customers_detail.html',{'customer_form':form})
提交内容:
查看结果:
12.4.增加验证及显示必填
{% extends 'base.html' %} {% load custom_page %} {% block page-header %} 客户详细信息 {% endblock %} {% block page-content %} <!-- 新增提交form --> <form class="form-horizontal" method="post">{% csrf_token %} <!-- 循环每个字段,增加样式 --> {% for filed in customer_form %} <div class="form-group"> <!-- 如果字段比填 --> {% if filed.field.required %} <!-- 字段前面加* --> <label for="inputEmail3" class="col-sm-2 control-label">*{{ filed.label }}</label> {% else %} <!-- 非必须,则不加,此外字体变细 --> <label style="font-weight: normal" for="inputEmail3" class="col-sm-2 control-label">{{ filed.label }}</label> {% endif %} <div class="col-sm-10"> {{ filed }} {% if filed.errors %} <ul> {% for err in filed.errors %} <li style="color: #ff0e2e">{{ err }}</li> {% endfor %} </ul> {% endif %} </div> </div> {% endfor %} <!-- 按钮样式 --> <div class="col-sm-12"> <input class="btn btn-success pull-right" type="submit" value="Save"> </div> </form> {% endblock %}
查看结果:
13.权限管理
13.1.增加表字段
表字段,临时随机找的表增加
class UserProfile(models.Model): User = models.OneToOneField(User) name = models.CharField(max_length=64) school = models.ForeignKey('School') def __str__(self): return self.name class Meta: permissions = ( ('view_customer_list','可以查看客户列表'), ('view_customer_info','查看客户详细信息'), ('edit_own_customer_info','可以修改自己客户信息'), )
13.2.运行添加
13.3.先说URL别名
13.3.1.django的url别名很灵活
如果要访问:http://127.0.0.1:8000/cklcrm/customers/2/
后面的 2 如果写死就不好了,无法匹配到后面的3,4 ..等
from django.conf.urls import url,include from django.contrib import admin from cklcrm import views urlpatterns = [ url(r'^$',views.dashboard), url(r'^customers/$',views.customers), url(r'^customers/(\d+)/$',views.customsers_detail,name="customer_detail"), #此处使用了别名 ]
13.3.2.返回页面修改访问url
原:
<td><a href="/cklcrm/customers/{ customer.id }}">{ customer.id }}</a></td>
现:
<td><a href="{% url 'customer_detail' customer.id %}">{{ customer.id }}</a></td>
url 是调用路径
'customer_detail' 是调用的url别名
customer.id 是url的id
13.3.3.查看元素
13.4.继续接 13.2.
增加url别名
from django.conf.urls import url,include from django.contrib import admin from cklcrm import views urlpatterns = [ url(r'^$',views.dashboard), url(r'^customers/$',views.customers,name="customer_list"), url(r'^customers/(\d+)/$',views.customsers_detail,name="customer_detail"), ]
13.5.权限认证部分
新建文件:
#!/usr/bin/env python # -*- coding: utf-8 -*- from django.core.urlresolvers import resolve from django.shortcuts import render,redirect perm_dic = { 'view_customer_list': ['customer_list','GET',[]], 'view_customer_info': ['customer_detail','GET',[]], 'edit_own_customer_info': ['customer_detail','POST',['test']], } def perm_check(*args,**kwargs): request = args[0] #resolve将路径封装成返回的url别名 url_resovle_obj = resolve(request.path_info) #查找url,是否匹配成功 current_url_namespace = url_resovle_obj.url_name #app_name = url_resovle_obj.app_name #use this name later print("url namespace:",current_url_namespace) #设置一个变量,默认为false matched_flag = False matched_perm_key = None #必须设置url别名 if current_url_namespace is not None:#if didn't set the url namespace, permission doesn't work print("find perm...") #循环字典加入新的字典 for perm_key in perm_dic: perm_val = perm_dic[perm_key] #字典长度必须大于3 if len(perm_val) == 3:#otherwise invalid perm data format url_namespace,request_method,request_args = perm_val print(url_namespace,current_url_namespace) #判断url if url_namespace == current_url_namespace: #判断方法 if request.method == request_method: #如果参数为空,则匹配到权限 if not request_args:#if empty , pass matched_flag = True matched_perm_key = perm_key print('mtched...') break #no need looking for other perms else: #如果参数不为空,则循环参数 for request_arg in request_args: #might has many args request_method_func = getattr(request,request_method) #get or post mostly #print("----->>>",request_method_func.get(request_arg)) if request_method_func.get(request_arg) is not None: matched_flag = True # the arg in set in perm item must be provided in request data else: matched_flag = False print("request arg [%s] not matched" % request_arg) break #no need go further if matched_flag == True: # means passed permission check ,no need check others print("--passed permission check--") matched_perm_key = perm_key break else:#permission doesn't work return True if matched_flag == True: #pass permission check perm_str = "crm.%s" %(matched_perm_key) if request.user.has_perm(perm_str): print("\033[42;1m--------passed permission check----\033[0m") return True else: print("\033[41;1m ----- no permission ----\033[0m") print(request.user,perm_str) return False else: print("\033[41;1m ----- no matched permission ----\033[0m") def check_permission(func): def wrapper(*args,**kwargs): print("--start check permission --") if perm_check(*args,**kwargs) is not True: return render(args[0],'cklcrm/403.html') return func(*args,**kwargs) return wrapper
13.6.装饰器应用views.py
from django.shortcuts import render,redirect from cklcrm import models from cklcrm import forms # Create your views here. from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger from cklcrm.permissions import check_permission def dashboard(request): return render(request,'cklcrm/dashboard.html') @check_permission def customers(request): customers_list = models.Customer.objects.all() paginator = Paginator(customers_list,3) page = request.GET.get('page') try: customer_pages = paginator.page(page) except PageNotAnInteger: customer_pages = paginator.page(1) except EmptyPage: customer_pages = paginator.page(paginator.num_pages) # return render(request,'cklcrm/customers.html',{'customers_list':customers_list}) return render(request, 'cklcrm/customers.html', {'customers_list': customer_pages}) @check_permission def customsers_detail(request,customer_id): customer_obj = models.Customer.objects.get(id=customer_id) if request.method == "POST": #不加instance=customer_obj,就是创建一条新记录,而不是更新数据 form = forms.CustomerModelForm(request.POST,instance=customer_obj) if form.is_valid(): form.save() #获取到首页的url,并返回 base_url = "/".join(request.path.split("/")[0:-2]) return redirect(base_url) else: form = forms.CustomerModelForm(instance=customer_obj) return render(request,'cklcrm/customers_detail.html',{'customer_form':form})
13.7.配置返回页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>403</title> </head> <body> <h1 style="font-size: 100px">403</h1> <h2>You cannot access this page,check your permission !</h2> </body> </html>
13.8.普通用户登录
进入访问页面:
13.8.添加列表访问权限