1.创建新项目
2.设计数据库表
from django.db import models# Create your models here.from django.contrib.auth.models import Usercourse_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.nameclass UserProfile(models.Model): User = models.OneToOneField(User) name = models.CharField(max_length=64) school = models.ForeignKey('School') def __unicode__(self): return self.nameclass 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.customerclass 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.nameclass 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 pymysqlpymysql.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 adminimport 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 ConfigurationThe `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,includefrom django.contrib import adminurlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^cklcrm/',include('cklcrm.urls'))]
6.2.配置cklcrm url
from django.conf.urls import url,includefrom django.contrib import adminfrom cklcrm import viewsurlpatterns = [ 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
{% block page-header %}You page{% endblock %}
{% block page-content %} Your page haha {% endblock %}
7.3.修改dashboard.html
{% extends 'base.html' %}{ % block page-header %} CKL dashboard{ % endblock %}
查看页面:
8.添加客户管理信息表
8.1.新增views方法
from django.shortcuts import renderfrom 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 }}
ID | 姓名 | 渠道 | 咨询课程 | 课程类型 | 客户备注 | 状态 | 课程顾问 | 日期 | |
---|---|---|---|---|---|---|---|---|---|
{ { customer.id }} | { { customer.qq }} | { { customer.name }} | { { customer.source_type }} | { { customer.course }} | { { customer.course_type }} | { { customer.consult_memo }} | { { customer.status }} | { { customer.consultant }} | { { customer.date }} |
查看结果:
9.2.字段名称显示中文
修改html
{ { customer.id }} { { customer.qq }} { { customer.name }} { { customer.source_type }} { { customer.course }} { { customer.get_course_type_display }} { { customer.consult_memo }} { { customer.get_status_display }} { { customer.consultant }} { { customer.date }}
查看修改结果:
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.增加显示样式
{ { customer.id }} { { customer.qq }} { { customer.name }} { { customer.source_type }} { { customer.course }} { { customer.get_course_type_display }} { { customer.consult_memo|truncatewords:10 }} { { customer.get_status_display }} { { customer.consultant }} { { customer.date }}
查看结果:
11.分页
11.1.django分页模块
https://docs.djangoproject.com/en/2.0/topics/pagination/
11.2.新增数据
11.3.配置分页
11.3.1.配置后端返回
from django.shortcuts import renderfrom cklcrm import models# Create your views here.from django.core.paginator import Paginator,EmptyPage,PageNotAnIntegerdef 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.配置前端返回
在表格下面新增如下:
11.3.查看页面
11.4.分页优化一
11.4.1.增加如下样式
https://v3.bootcss.com/components/#pagination
11.4.2.前端展示增加
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 templateregister = template.Library()@register.filterdef 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 templatefrom django.utils.html import format_htmlregister = template.Library()@register.filterdef ckl_upper(val): print("-- from my temp:") return val.upper()#传入多个参数使用如下@register.simple_tagdef neb_page(current_num,loop_num): #获取当前页及循环页的偏移量 offset = abs(current_num - loop_num) #如果小于3则 if offset < 3: #如果循环页等于当前页,就给页码加色 if loop_num == current_num: page_ele = '''
11.6.2.前端返回定义
{% extends 'base.html' %}{% load custom_page %}{% block page-header %} 客户管理信息列表{% endblock %}{% block page-content %}
ID | 姓名 | 渠道 | 咨询课程 | 课程类型 | 客户备注 | 状态 | 课程顾问 | 日期 | |
---|---|---|---|---|---|---|---|---|---|
{ { customer.id }} | { { customer.qq }} | { { customer.name }} | { { customer.source_type | ckl_upper}} | { { customer.course }} | { { customer.get_course_type_display }} | { { customer.consult_memo|truncatechars:30 }} | { { customer.get_status_display }} | { { customer.consultant }} | { { customer.date }} |
查看结果:
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,includefrom django.contrib import adminfrom cklcrm import viewsurlpatterns = [ 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,ModelFormfrom cklcrm import modelsclass CustomerModelForm(ModelForm): class Meta: model = models.Customer exclude = ()
12.1.4.配置views方法
from django.shortcuts import renderfrom cklcrm import models #导入formsfrom cklcrm import forms# Create your views here.from django.core.paginator import Paginator,EmptyPage,PageNotAnIntegerdef 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,ModelFormfrom cklcrm import modelsclass 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,ModelFormfrom cklcrm import modelsclass 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 %}{% endblock %}
12.3.提交修改
12.3.1.修改views方法
from django.shortcuts import render,redirectfrom cklcrm import modelsfrom cklcrm import forms# Create your views here.from django.core.paginator import Paginator,EmptyPage,PageNotAnIntegerdef 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 %}{% 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,includefrom django.contrib import adminfrom cklcrm import viewsurlpatterns = [ url(r'^$',views.dashboard), url(r'^customers/$',views.customers), url(r'^customers/(\d+)/$',views.customsers_detail,name="customer_detail"), #此处使用了别名]
13.3.2.返回页面修改访问url
原:
现:
url 是调用路径
'customer_detail' 是调用的url别名
customer.id 是url的id
13.3.3.查看元素
13.4.继续接 13.2.
增加url别名
from django.conf.urls import url,includefrom django.contrib import adminfrom cklcrm import viewsurlpatterns = [ 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 resolvefrom django.shortcuts import render,redirectperm_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,redirectfrom cklcrm import modelsfrom cklcrm import forms# Create your views here.from django.core.paginator import Paginator,EmptyPage,PageNotAnIntegerfrom cklcrm.permissions import check_permissiondef dashboard(request): return render(request,'cklcrm/dashboard.html')@check_permissiondef 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_permissiondef 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.配置返回页面
403 403
You cannot access this page,check your permission !
13.8.普通用户登录
进入访问页面:
13.8.添加列表访问权限