巨蟒django之CRM2 展示客户列表&&分页
1.展示客户列表
点击画红线中的views,进入下列界面
路径的查找顺序:应该是先查找外层的templates里边的html,然后查找app里边的templates
另一个会按照app的顺序进行寻找,在一开始的settings.py里边的配置文件
模板:
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>路飞学城</title> <link rel="shortcut icon" href="{% static 'imgs/luffy-study-logo.png' %} "> <link rel="stylesheet" href="{% static 'plugins/bootstrap/css/bootstrap.css' %} "/> <link rel="stylesheet" href="{% static 'plugins/font-awesome/css/font-awesome.css' %} "/> <link rel="stylesheet" href="{% static 'css/commons.css' %} "/> <link rel="stylesheet" href="{% static 'css/nav.css' %} "/> <style> body { margin: 0; } .no-radius { border-radius: 0; } .no-margin { margin: 0; } .pg-body > .left-menu { background-color: #EAEDF1; position: absolute; left: 1px; top: 48px; bottom: 0; width: 220px; border: 1px solid #EAEDF1; overflow: auto; } .pg-body > .right-body { position: absolute; left: 225px; right: 0; top: 48px; bottom: 0; overflow: scroll; border: 1px solid #ddd; border-top: 0; font-size: 13px; min-width: 755px; } .navbar-right { float: right !important; margin-right: -15px; } .luffy-container { padding: 15px; } .left-menu .menu-body .static-menu { } .left-menu .menu-body .static-menu .icon-wrap { width: 20px; display: inline-block; text-align: center; } .left-menu .menu-body .static-menu a { text-decoration: none; padding: 8px 15px; border-bottom: 1px solid #ccc; color: #333; display: block; background: #efefef; background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #efefef), color-stop(1, #fafafa)); background: -ms-linear-gradient(bottom, #efefef, #fafafa); background: -o-linear-gradient(bottom, #efefef, #fafafa); filter: progid:dximagetransform.microsoft.gradient(startColorStr='#e3e3e3', EndColorStr='#ffffff'); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fafafa',EndColorStr='#efefef')"; box-shadow: inset 0 1px 1px white; } .left-menu .menu-body .static-menu a:hover { color: #2F72AB; border-left: 2px solid #2F72AB; } .left-menu .menu-body .static-menu a.active { color: #2F72AB; border-left: 2px solid #2F72AB; } </style> {% block css %} {% endblock %} </head> <body> <div class="pg-header"> <div class="nav"> <div class="logo-area left"> <a href="#"> <img class="logo" src="{% static 'imgs/logo.svg' %}"> <span style="font-size: 18px;">路飞学城 </span> </a> </div> <div class="left-menu left"> <a class="menu-item">资产管理</a> <a class="menu-item">用户信息</a> <a class="menu-item">路飞管理</a> <div class="menu-item"> <span>使用说明</span> <i class="fa fa-caret-down" aria-hidden="true"></i> <div class="more-info"> <a href="#" class="more-item">管他什么菜单</a> <a href="#" class="more-item">实在是编不了</a> </div> </div> </div> <div class="right-menu right clearfix"> <div class="user-info right"> <a href="#" class="avatar"> <img class="img-circle" src="{% static 'imgs/default.png' %}"> </a> <div class="more-info"> <a href="#" class="more-item">个人信息</a> <a href="#" class="more-item">注销</a> </div> </div> <a class="user-menu right"> 消息 <i class="fa fa-commenting-o" aria-hidden="true"></i> <span class="badge bg-success">2</span> </a> <a class="user-menu right"> 通知 <i class="fa fa-envelope-o" aria-hidden="true"></i> <span class="badge bg-success">2</span> </a> <a class="user-menu right"> 任务 <i class="fa fa-bell-o" aria-hidden="true"></i> <span class="badge bg-danger">4</span> </a> </div> </div> </div> <div class="pg-body"> <div class="left-menu"> <div class="menu-body"> <div class="static-menu"> <a href="/crm/depart/list/"><span class="icon-wrap"><i class="fa fa-map-o" aria-hidden="true"></i></span> 部门管理</a> <a href="/crm/user/list/"><span class="icon-wrap"><i class="fa fa-map-o" aria-hidden="true"></i></span> 用户管理</a> </div> </div> </div> <div class="right-body"> <div> <ol class="breadcrumb no-radius no-margin" style="border-bottom: 1px solid #ddd;"> <li><a href="#">首页</a></li> <li class="active">客户管理</li> </ol> </div> {% block content %} {% endblock %} </div> </div> <script src="{% static 'js/jquery-3.3.1.min.js' %} "></script> <script src="{% static 'plugins/bootstrap/js/bootstrap.js' %} "></script> {% block js %} {% endblock %} </body> </html>
将这两个css样式放到静态文件下的css样式里边
插件放到项目的对应位置
将图片放到对应的位置
具体放入的位置如下图:
app也就是crm中的模板templates创建的customer_list.html需要继承layout.html文件,如下所示:
运行项目,得到如下结果:
上边是布局的整体结构内容
块级钩子
找到表结构中的内容进行对应
先查询出所有信息
运行:
下面我们学习创建超级用户
创建超级用户,用户名root,邮箱可以不填写,密码至少是8位不能是纯数字,也不能全部是字母
在这里我填写的超级用户的密码是:root123456
在浏览器中打开,
输入刚才创建的超级用户
点击登录:
这是自身创建的表
现在需要注册自己的模型,在自己的app模型下边
再次运行,得到下面的界面
点击Customers,就可以进行添加操作了
表需要一一注册
将设置里边设置成中文的形式
这个时候,显示的就是中文了,深色表示必填的信息,浅色表示选填的信息
总结:
1. 展示客户列表
使用admin
1. 创建超级用户
Python manage.py createsuperuser
2. 注册model
在APP下的admin.py中注册
from django.contrib import admin
from crm import models
# Register your models here.
admin.site.register(models.Customer)
我们看到,顾客表和班级表是多对多的对应关系(也就是当前客户和已报班级是一对一的对应关系)
多对多的关系通过第三张表进行维护,也可以不填写,但是下面的,是必须填写的
null=True,表示数据库可以为空,blank=True表示填写表单的时候可以为空
显示的对象如下图:
修改str,显示名字,下面修改的类是customer
刷新之后,得到的结果:
我们也可以点击进去修改名字:
我们也需要选择销售的str方法
我们需要在UserProfile类,写上str方法目的是销售
这个时候就可以显示出来销售的名字了
班级也要显示,我们需要对班级表进行管理
也就是我们需要在admin里边注册上班级表&&校区表
运行之后,得到的结果,点击进去,进行添加
也可以在这个位置进行添加,
注意下面的红线走向
选中之后,保存
再添加一条数据:
下面开始展示数据效果:
开始加样式
运行,得到结果:
通过名字进行用过滤器进行填写
通过点sex拿到后边对应的值,男或者女?
下面是前端,提供的一个方法:
这样,我们就拿到了对应的结果:
就是因为下面的属性引起的
上边的原因是,前端的代码是有顺序的,调整之后已经正常了,得到下面的结果:
出生日期也是会根据settings.py的语言环境的变化而发生变化的
下面我们改成中文环境
运行:这个时候就会发生了变化
我们也可以看到这个字段是DataField字段,下面我们进行操作
得到结果:
这个日期需要一个一个改,有什么办法可以进行一次修改吗???
只需要进行配置一个东西
现在,我们去掉过滤日期的类型,依然得到下面的结果:
运行之后,依然得到下面的结果:
年月日,时分秒
总结:
展示不同字段的方式:
1. 普通字段
对象.字段名
2. choices
对象.字段名 -> 真实的值
对象.get_字段名_display() -> 中文显示值
3. 外键
对象.外键 —— 》 定义str
对象.外键.name
4. 其他
定义函数
def show_class(self):
return ' | '.join([ str(i) for i in self.class_list.all()])
日期格式化的配置:
USE_L10N = False
DATE_FORMAT = 'Y-m-d'
DATETIME_FORMAT = 'Y-m-d H:i:s'
后端safe
from django.utils.safestring import mark_safe
绑定销售之后,直接得到下面的结果:
也就是因为定义了这个方法
外键:
得到的结果是:
多对多拿到的结果是,管理对象,也就是另一个对象,我们想要拿到锁关联的班级,上图显示的已报班级是一个(crm.ClassList.None)
得到的结果是:
得到的结果不好看,我们可以通过这个多对多的接口定义方法:
我们在前端,再写一行,看显示的结果:
运行:
,现在我们需要,自定义方法,得到我们需要的结果
如何展示这个班级?
这个自定义函数里边的self代表什么?指的是当前类Customer的对象
首先处理班级列表里边的内容:
我们在用户表(Customer)里边,调用班级表(ClassList)
class_list就是上边的接口,多对多,也就是Customer表
运行,得到下图的结果:
校区没有显示具体的名字,我们现在定义一下
因为,班级列表ClassList和校区列表(Campuses)是外键关系
得到如下所示的结果:
我们在admin里边选择两个班级,得到的结果是:
运行:
我们再写状态
注释掉电话
修改状态:
虽然可以显示出来,但是状态不明显.
状态内容,修改成背景颜色
向外扩充一点padding:2px
我们可以想办法在后端处理这个事情,在customer类中
在前端,调用这个函数
现在,我们看到的是字符串
只需要在前端加上safe
这样就可以成功显示结果了
颜色需要调整一下,做判断或者设置对应关系,通过字典
点击"进去",拿到下面的四种状态.
这样就成功实现了颜色的区分
如果不想在前端显示这个状态safe,在后端写
导入模块
用这个安全模块进行包裹
运行:依然可以得到想要的结果
对颜色进行修改:
通过右下角进行颜色的选择
2.分页
(1) 展示所有页面
数据量比较少,如何做?
写一个测试页面,在项目下,添加路由urls.py
分页,点击上边的views,进入下面界面,也就是crm里边的views.py文件
将得到的字典,返回到前端页面
运行:
分页的目的是,几条一页
如何处理这些数据?
运行之后,服务端得到的值是1
下面进行判断一下
数字小于1,输入的页码不是数字
输入页码错误会报错
在后边我们进行切片
这样一页就是20条数据
在bootstrap中找到组件里边的分页功能代码
这个时候就有了
最后只留下一个,通过循环,得到即可
也就是总的数据量除以显示的数据量,也就是余数的问题
鼠标放到1上,可以看到左下角的地址,点击就可以实现功能了
(2)处理左右极值
下面进行限制一下,因为太长了页码数
前后都显示5个,(设置当前显示的页码数)
#最大显示的页码数
如何动态的显示下面的界面?
成功改变了
当前的问题,如何处理极值的问题
前后都多了
数据量少,不够怎么办?最大值和最小值问题?
(3)添加上下页和选中
运行:(相当于在后端对其进行循环)
如何加上一页和下一页?
加头加尾
走到1,上边就不能点了
最后边这个需要写在最后边的.
如何让页面显示的更突出一些?
(4)封装成类以及使用
升级,从函数调用到封装成类
在整个项目下新建文件utils,在其中建立一个分页(pagination.py)PY文件
views.py
from django.shortcuts import render,redirect,reverse,HttpResponse from crm import models from crm.froms import RegForm import hashlib from utils.pagination import Pagination # Create your views here. def index(request): return HttpResponse('index') def login(request): # print(request.POST) # 获取用户名和密码与数据库中的数据对比 if request.method=='POST': user=request.POST.get('username') pwd=request.POST.get('password') md5 = hashlib.md5() md5.update(pwd.encode('utf-8')) pwd = md5.hexdigest() obj=models.UserProfile.objects.filter(username=user,password=pwd,is_active=True).first() if obj: #登录成功,跳转到主页面 return redirect(reverse('index')) else: #登录失败 return render(request,'login.html',{'error':'用户名或密码错误'}) # is_active表示为true的状态下,才能够登录 return render(request,'login.html') #注册 def reg(request): form_obj=RegForm() #判断请求方式 if request.method=='POST': form_obj=RegForm(request.POST) #对数据进行校验 if form_obj.is_valid(): #is_valid是对数据进行校验 #内置校验,校验器的方法,钩子,判断是否有,内部只有clean方法 #数据正确 插入数据库 # print(form_obj.cleaned_data) # form_obj.cleaned_data.pop('re_password') # models.UserProfile.objects.create(**form_obj.cleaned_data) form_obj.save() return redirect(reverse('login')) return render(request,'reg.html',{'form_obj':form_obj}) #展示客户列表 def customer_list(request): all_customer = models.Customer.objects.all() return render(request,'customer_list.html',{'all_customer':all_customer}) users=[{'name':"alex{}".format(i),'pwd':'123'} for i in range(1,302)] #分页 # def user_list(request): # ''' # 一页显示20条 # 第1页 0 20 # 第2页 20 40 # ... # 第n页 (n-1)20 20n # :param request: # :return: # ''' # #获取页码 # try: # page_num=int(request.GET.get('page','1')) #默认值为1 # if page_num<=0: # page_num=1 # except Exception as e: # page_num=1 # #每页显示的数据量 # per_num=10 # # #总数据量 # all_count=len(users) # #总页码数 # page_count,more=divmod(all_count,per_num) #商数,余数 # if more: # page_count+=1 # #最大显示页码数 # max_show=11 # half_show=max_show//2 # # #总页码数<最大显示页码数 # if page_count<max_show: # page_start=1 # page_end=page_count # else: # #处理左边极值 # if page_num<=half_show: # page_start=1 # page_end=max_show #也可以直接写11 # #处理右边极值 # elif page_num+half_show>=page_count: # page_start=page_count-max_show+1 # page_end=page_count # else: # page_start=page_num-half_show # page_end=page_num+half_show # page_list=[] # if page_num==1: # page_list.append('<li class="disabled"><a>上一页</a></li>') # else: # page_list.append('<li><a href="?page={}">上一页</a></li>'.format(page_num-1,)) # for i in range(page_start,page_end+1): # if i==page_num: # page_list.append('<li class="active"><a href="?page={}">{}</a></li>'.format(i,i)) # else: # page_list.append('<li><a href="?page={}">{}</a></li>'.format(i,i)) # if page_num==page_count: # page_list.append('<li class="disabled"><a>下一页</a></li>') # else: # page_list.append('<li><a href="?page={}">下一页</a></li>'.format(page_num+1,)) # page_html = ''.join(page_list) # # return render(request,'user_list.html',{'users':users[(page_num-1)*per_num:per_num*page_num],'page_count':range(1,page_count+1)}) # # return render(request,'user_list.html',{'users':users[(page_num-1)*per_num:per_num*page_num],'page_count':range(2,12+1)}) # # return render(request,'user_list.html',{'users':users[(page_num-1)*per_num:per_num*page_num],'page_count':range(page_start,page_end+1)}) # return render(request,'user_list.html',{'users':users[(page_num-1)*per_num:per_num*page_num],'page_html':page_html}) # 分页 def user_list(request): ''' 一页显示20条 第1页 0 20 第2页 20 40 ... 第n页 (n-1)20 20n :param request: :return: ''' page=Pagination(request.GET.get('page',1),len(users)) return render(request, 'user_list.html', {'users': users[page.start:page.end], 'page_html':page.page_html })
pagination.py
# Author: studybrother sun class Pagination: def __init__(self,page_num,all_count,per_num = 10,max_show = 11): # 获取页码 try: # page_num = int(request.GET.get('page', '1')) # 默认值为1 self.page_num = int(page_num) # 默认值为1 if self.page_num <= 0: self.page_num = 1 except Exception as e: self.page_num = 1 # 每页显示的数据量 self.per_num = per_num # 总数据量 all_count = all_count # 总页码数 self.page_count, more = divmod(all_count, per_num) # 商数,余数 if more: self.page_count += 1 # 最大显示页码数 self.max_show = 11 self.half_show = max_show // 2 @property def page_html(self): # 总页码数<最大显示页码数 if self.page_count < self.max_show: page_start = 1 page_end = self.page_count else: # 处理左边极值 if self.page_num <= self.half_show: page_start = 1 page_end = self.max_show # 也可以直接写11 # 处理右边极值 elif self.page_num + self.half_show >= self.page_count: page_start = self.page_count - self.max_show + 1 page_end = self.page_count else: page_start = self.page_num - self.half_show page_end = self.page_num + self.half_show page_list = [] if self.page_num == 1: page_list.append('<li class="disabled"><a>上一页</a></li>') else: page_list.append('<li><a href="?page={}">上一页</a></li>'.format(self.page_num - 1, )) for i in range(page_start, page_end + 1): if i == self.page_num: page_list.append('<li class="active"><a href="?page={}">{}</a></li>'.format(i, i)) else: page_list.append('<li><a href="?page={}">{}</a></li>'.format(i, i)) if self.page_num == self.page_count: page_list.append('<li class="disabled"><a>下一页</a></li>') else: page_list.append('<li><a href="?page={}">下一页</a></li>'.format(self.page_num + 1, )) # page_html = ''.join(page_list) return ''.join(page_list) # 最后需要的就是这个 #开始 @property def start(self): ''' 切片起始值 :return: ''' return (self.page_num-1)*self.per_num @property def end(self): ''' 切片终止值 :return: ''' return (self.page_num)*self.per_num
user_list.html
{% extends 'layout.html' %} {% block content %} <table class="table table-hover table-bordered"> {% for user in users %} <tr> <td>{{ user.name }}</td> <td>{{ user.pwd }}</td> </tr> {% endfor %} </table> <nav aria-label="Page navigation"> <ul class="pagination"> {# {% for page in page_count %}#} {# <li><a href="?page={{ page }}">{{ page }}</a></li>#} {# {% endfor %}#} {{ page_html|safe }} </ul> </nav> {% endblock %}
layout.html
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>路飞学城</title> <link rel="shortcut icon" href="{% static 'img/luffy-study-logo.png' %} "> <link rel="stylesheet" href="{% static 'plugins/bootstrap/css/bootstrap.css' %} "/> <link rel="stylesheet" href="{% static 'plugins/font-awesome/css/font-awesome.css' %} "/> <link rel="stylesheet" href="{% static 'css/commons.css' %} "/> <link rel="stylesheet" href="{% static 'css/nav.css' %} "/> <style> body { margin: 0; } .no-radius { border-radius: 0; } .no-margin { margin: 0; } .pg-body > .left-menu { background-color: #EAEDF1; position: absolute; left: 1px; top: 48px; bottom: 0; width: 220px; border: 1px solid #EAEDF1; overflow: auto; } .pg-body > .right-body { position: absolute; left: 225px; right: 0; top: 48px; bottom: 0; overflow: scroll; border: 1px solid #ddd; border-top: 0; font-size: 13px; min-width: 755px; } .navbar-right { float: right !important; margin-right: -15px; } .luffy-container { padding: 15px; } .left-menu .menu-body .static-menu { } .left-menu .menu-body .static-menu .icon-wrap { width: 20px; display: inline-block; text-align: center; } .left-menu .menu-body .static-menu a { text-decoration: none; padding: 8px 15px; border-bottom: 1px solid #ccc; color: #333; display: block; background: #efefef; background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #efefef), color-stop(1, #fafafa)); background: -ms-linear-gradient(bottom, #efefef, #fafafa); background: -o-linear-gradient(bottom, #efefef, #fafafa); filter: progid:dximagetransform.microsoft.gradient(startColorStr='#e3e3e3', EndColorStr='#ffffff'); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fafafa',EndColorStr='#efefef')"; box-shadow: inset 0 1px 1px white; } .left-menu .menu-body .static-menu a:hover { color: #2F72AB; border-left: 2px solid #2F72AB; } .left-menu .menu-body .static-menu a.active { color: #2F72AB; border-left: 2px solid #2F72AB; } </style> {% block css %} {% endblock %} </head> <body> <div class="pg-header"> <div class="nav"> <div class="logo-area left"> <a href="#"> <img class="logo" src="{% static 'img/logo.svg' %}"> <span style="font-size: 18px;">路飞学城 </span> </a> </div> <div class="left-menu left"> <a class="menu-item">资产管理</a> <a class="menu-item">用户信息</a> <a class="menu-item">路飞管理</a> <div class="menu-item"> <span>使用说明</span> <i class="fa fa-caret-down" aria-hidden="true"></i> <div class="more-info"> <a href="#" class="more-item">管他什么菜单</a> <a href="#" class="more-item">实在是编不了</a> </div> </div> </div> <div class="right-menu right clearfix"> <div class="user-info right"> <a href="#" class="avatar"> <img class="img-circle" src="{% static 'img/default.png' %}"> </a> <div class="more-info"> <a href="#" class="more-item">个人信息</a> <a href="#" class="more-item">注销</a> </div> </div> <a class="user-menu right"> 消息 <i class="fa fa-commenting-o" aria-hidden="true"></i> <span class="badge bg-success">2</span> </a> <a class="user-menu right"> 通知 <i class="fa fa-envelope-o" aria-hidden="true"></i> <span class="badge bg-success">2</span> </a> <a class="user-menu right"> 任务 <i class="fa fa-bell-o" aria-hidden="true"></i> <span class="badge bg-danger">4</span> </a> </div> </div> </div> <div class="pg-body"> <div class="left-menu"> <div class="menu-body"> <div class="static-menu"> <a href="/crm/depart/list/"><span class="icon-wrap"><i class="fa fa-map-o" aria-hidden="true"></i></span> 部门管理</a> <a href="/crm/user/list/"><span class="icon-wrap"><i class="fa fa-map-o" aria-hidden="true"></i></span> 用户管理</a> </div> </div> </div> <div class="right-body"> <div> <ol class="breadcrumb no-radius no-margin" style="border-bottom: 1px solid #ddd;"> <li><a href="#">首页</a></li> <li class="active">客户管理</li> </ol> </div> {% block content %} {% endblock %} </div> </div> <script src="{% static 'js/jquery-3.3.1.min.js' %} "></script> <script src="{% static 'plugins/bootstrap/js/bootstrap.js' %} "></script> {% block js %} {% endblock %} </body> </html>