1.靓号表
1.1 表结构
1.2 靓号表的构造
class PrettyNum(models.Model):
''' 靓号表 '''
mobile = models.CharField(verbose_name="手机号", max_length=11)
# default 默认值
# null = true,blank = true 允许为空
price = models.IntegerField(verbose_name="价格", default=0)
# 号码等级采用choice
level_choices = (
(1, "1级"),
(2, "2级"),
(3, "3级"),
(4, "4级"),
)
# 默认等级为1
level = models.SmallIntegerField(verbose_name="级别", choices=level_choices, default=level_choices[0][0])
# 号码状态也采用choice
status_choices = (
(1, "已占用"),
(2, "未使用"),
)
# 默认状态为2(未使用)
status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=status_choices[1][0])
# 号码等级采用choice level_choices = ( (1, "1级"), (2, "2级"), (3, "3级"), (4, "4级"), ) # 默认等级为1 level = models.SmallIntegerField(verbose_name="级别", choices=level_choices, default=level_choices[0][0])
特别注意:choice类型的数据的获取,采用get_xxx_display
默认值的设置
元组的获取:
( (1, “1级”),(2, “2级”),(3, “3级”),(4, “4级”) )
level_choices[0] [0] = 1
level_choices[0] [1] = “1级”
2.靓号列表及查询操作
number.html
{% extends 'layout.html' %}
{% block content %}
<div style="margin-bottom: 10px">
<a type="button" class="btn btn-success" href="/number/add"><span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span> 添加靓号</a>
<div style="width: 300px; float: right">
<form method="get" action="/number/list">
<div class="input-group">
<input type="text" class="form-control" name="mobile" placeholder="Search for...">
<span class="input-group-btn">
<button class="btn btn-default" type="submit"><span class="glyphicon glyphicon-search"
aria-hidden="true"></span></button>
</span>
</div>
</form>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">靓号列表</div>
<div class="bs-example" data-example-id="hoverable-table">
<table class="table table-hover">
<thead>
<tr>
<th>ID</th>
<th>号码</th>
<th>价格</th>
<th>级别</th>
<th>状态</th>
</tr>
</thead>
<tbody>
{% for number in NumList %}
<tr>
<td>{{ number.id }}</td>
<td>{{ number.mobile }}</td>
<td>{{ number.price }}</td>
{# choice 类型采用get_xxx_display 方式获取 #}
<td>{{ number.get_level_display }}</td>
<td>{{ number.get_status_display }}</td>
<td>
<a class="btn btn-warning btn-sm" href="/number/{{ number.id }}/update">编辑</a>
<a class="btn btn-danger btn-sm" href="/number/del?nid={{ number.id }}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
views.py
def number_list(request):
""" 靓号列表 """
# 利用get获取搜索条件
data_dict = {}
mobile = request.GET.get('mobile')
print(mobile)
if mobile:
# {关键字: 范围, }
data_dict['mobile__contains'] = mobile
# date_dict为空时,全部查找 不为空按条件查找
NumList = models.PrettyNum.objects.filter(**data_dict).order_by("-level")
return render(request, "number_list.html", {"NumList": NumList})
2.1Django中的条件查询
- 数据排序
order_by("level") 按照level正向排序 由低到高
order_by("-level") 按照level逆向排序 由高到低
-
条件查询列表
- 方式1 直接传
models.PrettyNum.objects.filter(mobile='15588886666', id=2)
- 方式2 传字典 { 关键字:范围, }
data_dict = {'mobile': '15588886666', 'id': 2} models.PrettyNum.objects.filter(**data_dict)
-
django中常见的条件
models.PrettyNum.objects.filter(id=2, mobile="15666662222") # id等于2且 mobile="15666662222"
models.PrettyNum.objects.filter(id__gt=2, mobile__startswith="198") # id大于2 且 mobile以198开头
models.PrettyNum.objects.filter(id__gte=2, mobile__endswith="999") # id大于等于2且 mobile以999结尾
models.PrettyNum.objects.filter(id__lt=2, mobile__contains="888") # id小于2且 mobile包含888
models.PrettyNum.objects.filter(id__lte=2) # id小于等于2
2.2条件查询的思路
data_dict = {}
mobile = request.GET.get('mobile')
print(mobile)
if mobile:
# {关键字: 范围, }
data_dict['mobile__contains'] = mobile
# date_dict为空时,全部查找 不为空按条件查找
NumList = models.PrettyNum.objects.filter(**data_dict).order_by("-level")
return render(request, "number_list.html", {"NumList": NumList})
<div style="width: 300px; float: right">
<form method="get" action="/number/list">
<div class="input-group">
<input type="text" class="form-control" name="mobile" placeholder="Search for...">
<span class="input-group-btn">
<button class="btn btn-default" type="submit"><span class="glyphicon glyphicon-search" aria-hidden="true"></span></button>
</span>
</div>
</form>
</div>
基本思路:采用get方式进行传递查询条件
- 无条件时
http://localhost:8000/number/list?mobile=
- 有查询条件时
http://localhost:8000/number/list?mobile=888
基本逻辑:
前端输入框,将输入的数据以get请求传到后端,后端
mobile = request.GET.get('mobile',"")
获取到前端传来的数据作为查询条件使用字典来接收所有条件
- 若前端传来的mobile为空,即无查询条件,则条件字典为空,默认查询所有数据
- 若前端传来的mobile非空,则讲条件添加到条件字典中。本案例使用模糊查询,date_dict={‘‘mobile__contains’’:mobile}
mobile字段只要含有获得数据mobile即可
2.3 分页查询操作
2.3.1 原始逻辑
思路:
- 构建html标签进行页面跳转 可以在python操作查询的数据集,构建标签字符串,传回前端渲染
- page_list存储每一个
- 标签
- page_str 整个页码的标签内容
- mark_safe使其page_str变得安全,以至于能渲染到html中
<li><a href="/number/list?page=1">1</a></li> <li><a href="/number/list?page=2">2</a></li> <li><a href="/number/list?page=3">3</a></li> <li><a href="/number/list?page=4">4</a></li> <li><a href="/number/list?page=5">5</a></li>
不加前面路径默认补充当前路径
< a href="/number/list?page=1"> = < a href="?page=1">
<li><a href="?page=1">1</a></li> <li><a href="?page=2">2</a></li> <li><a href="?page=3">3</a></li> <li><a href="?page=4">4</a></li> <li><a href="?page=5">5</a></li>
# i 表示页码 for i in range(page_start, page_end + 1): # 当前页面选中效果 if i == page: li = '<li class="active"><a href="?page= {}">{}</a></li>'.format(i, i) else: li = '<li><a href="?page= {}">{}</a></li>'.format(i, i) page_list.append(li) page_str = mark_safe(''.join(page_list)) # 分页功能的标签(html渲染) return render(request, "number_list.html", {"NumList": NumList, "mobile": mobile, "page_str": page_str})
数据库查询数据的截取
NumList = models.PrettyNum.objects.filter(**data_dict).order_by("-level")[data_start:data_end]
截取数据固定部分进行显示,是分页显示的核心利用get请求(在url中获取page的内容进行页面切换)
<li><a href="/number/list?page=1">1</a></li> page = int(request.GET.get('page', 1)) url:/number/list?page=1 则获取page = 1
页码范围大小、页面大小、首页、尾页、上一页、下一页、跳转页的逻辑判断
- 变量
page = int(request.GET.get('page', 1)) # 当前页码 page_size = 10 # 每页存放数据大小 data_start = (page - 1) * page_size # 页面显示数据的起始位置 data_end = page * page_size # 页面显示数据的末位置 # 数据库查询数据 NumList = models.PrettyNum.objects.filter(**data_dict).order_by("-level")[data_start:data_end] # 数据列表 data_count = models.PrettyNum.objects.filter(**data_dict).count() # 数据个数 page_count = int(data_count / page_size) + 1 # 页面个数 page_list = [] # 存放每一个<li>标签
- 首页与尾页
# 首页 first= '<li><a href="?page= {}">首页</a></li>'.format(1) page_list.append(first) # 尾页 last = '<li><a href="?page= {}">尾页</a></li>'.format(page_count) page_list.append(last)
- 上一页与下一页
first= '<li><a href="?page= {}">首页</a></li>'.format(1) page_list.append(first) # 上一页 if page > 1: prev = '<li><a href="?page= {}">上一页</a></li>'.format(page - 1) page_list.append(prev) else: prev = '<li><a href="?page= {}">上一页</a></li>'.format(page) page_list.append(prev) # 下一页 if page < page_count: next = '<li><a href="?page= {}">下一页</a></li>'.format(page + 1) page_list.append(next) else: next = '<li><a href="?page= {}">下一页</a></li>'.format(page) page_list.append(next)
- 页码范围区域+选中页面效果
# 可显示的页面区间 # i 表示页码 for i in range(page_start, page_end + 1): # 当前页面选中效果 if i == page: li = '<li class="active"><a href="?page= {}">{}</a></li>'.format(i, i) else: li = '<li><a href="?page= {}">{}</a></li>'.format(i, i) page_list.append(li)
- 跳转
<ul class="pagination"> {{ page_str }} <form method="get" style="display: inline-block"> <input type="text" name="page" style="width: 50px;height: 32px;margin-left: 2px"> <input type="submit" value="跳转"> </form> </ul>
number_list.html
{% extends 'layout.html' %}
{% block content %}
<div style="margin-bottom: 10px">
<a type="button" class="btn btn-success" href="/number/add"><span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span> 添加靓号</a>
<div style="width: 300px; float: right">
<form method="get" action="/number/list">
<div class="input-group">
<input type="text" class="form-control" name="mobile" placeholder="Search for..."
value="{{ mobile }}">
<span class="input-group-btn">
<button class="btn btn-default" type="submit"><span class="glyphicon glyphicon-search" aria-hidden="true"></span></button>
</span>
</div>
</form>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">靓号列表</div>
<div class="bs-example" data-example-id="hoverable-table">
<table class="table table-hover">
<thead>
<tr>
<th>ID</th>
<th>号码</th>
<th>价格</th>
<th>级别</th>
<th>状态</th>
</tr>
</thead>
<tbody>
{% for number in NumList %}
<tr>
<td>{{ number.id }}</td>
<td>{{ number.mobile }}</td>
<td>{{ number.price }}</td>
{# choice 类型采用get_xxx_display 方式获取 #}
<td>{{ number.get_level_display }}</td>
<td>{{ number.get_status_display }}</td>
<td>
<a class="btn btn-warning btn-sm" href="/number/{{ number.id }}/update">编辑</a>
<a class="btn btn-danger btn-sm" href="/number/del?nid={{ number.id }}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<ul class="pagination">
{{ page_str }}
<form method="get" style="display: inline-block">
<input type="text" name="page" style="width: 50px;height: 32px;margin-left: 2px">
<input type="submit" value="跳转">
</form>
</ul>
</div>
{% endblock %}
views.py
def number_list(request):
""" 靓号列表 """
# 利用get获取搜索条件
data_dict = {}
mobile = request.GET.get('mobile', "")
if mobile:
# {关键字: 范围, }
data_dict['mobile__contains'] = mobile
# date_dict为空时,全部查找 不为空按条件查找
"""分页功能"""
# 根据前端get请求获取page /number/list?page=xx
page = int(request.GET.get('page', 1)) # 当前页码
page_size = 10 # 每页存放数据大小
data_start = (page - 1) * page_size # 页面显示数据的起始位置
data_end = page * page_size # 页面显示数据的末位置
# 数据库查询数据
NumList = models.PrettyNum.objects.filter(**data_dict).order_by("-level")[data_start:data_end] # 数据列表
data_count = models.PrettyNum.objects.filter(**data_dict).count() # 数据个数
page_count = int(data_count / page_size) + 1 # 页面个数
page_list = [] # 存放每一个<li>标签
""" 页码
优化页码的显示 最多显示当前页码的加减五个
极值 判断前五页和后五页
"""
page_num_size = 5 # 最多显示页码的个数
# 数据较少,总页面没有达到11页
if page_count<=2*page_num_size+1:
page_start = 1
page_end = page_count
else:
if page <= page_num_size:
page_start = 1
page_end = page_num_size * 2 + 1
else:
if page + page_num_size >= page_count:
page_start = page_count - page_num_size * 2
page_end = page_count
else:
page_start = page - page_num_size
page_end = page + page_num_size
# 首页
first= '<li><a href="?page= {}">首页</a></li>'.format(1)
page_list.append(first)
# 上一页
if page > 1:
prev = '<li><a href="?page= {}">上一页</a></li>'.format(page - 1)
page_list.append(prev)
else:
prev = '<li><a href="?page= {}">上一页</a></li>'.format(page)
page_list.append(prev)
# 可显示的页面区间
# i 表示页码
for i in range(page_start, page_end + 1):
# 当前页面选中效果
if i == page:
li = '<li class="active"><a href="?page= {}">{}</a></li>'.format(i, i)
else:
li = '<li><a href="?page= {}">{}</a></li>'.format(i, i)
page_list.append(li)
# 下一页
if page < page_count:
next = '<li><a href="?page= {}">下一页</a></li>'.format(page + 1)
page_list.append(next)
else:
next = '<li><a href="?page= {}">下一页</a></li>'.format(page)
page_list.append(next)
# 尾页
last = '<li><a href="?page= {}">尾页</a></li>'.format(page_count)
page_list.append(last)
page_str = mark_safe(''.join(page_list)) # 分页功能的标签(html渲染)
return render(request, "number_list.html", {"NumList": NumList, "mobile": mobile, "page_str": page_str})
2.3.2 小bug
由于页面的条件查询也会在url中拼接一个mobile=xxx,分页查询时拼接的为page=xxx 但是上述代码url中无法同时存在mobile和page两个变量,因此无法实现查询时的分页功能
获取get请求中的所有url
http://localhost:8000/number/list?mobile=8888&page=1
query_dict = copy.deepcopy(request.GET)
copy.deepcopy(request.GET)返回url中所有拼接的变量,以字典的形式返回所有的url value以列表的形式<QueryDict: {'mobile': ['8888'], 'page': ['1']}>
query_dict.urlencode()
将所有的url拼接成字符串 mobile=8888&page=1
query_dict._mutable = True
保证含有url的字典能够增加新的关键字,更新urlurl的更新与拼接
更新url中的变量:
query_dict.setlist('page',[xx])
在原有的url中新增page= xx,value为列表值拼接url:
< li>< a href="/number/list?{}">< /a>< /li>'.format(query_dict.urlencode())
此时
query_dict.urlencode()=mobile=8888&page=xx
则代码拼接为/number/list?mobile=8888&page=xx
def number_list(request):
...
...
...
...
page = int(request.GET.get('page', '1')) # 当前页码
# copy.deepcopy(request.GET)返回url中所有拼接的变量
query_dict = copy.deepcopy(request.GET)
# 以字典的形式返回所有的url value以列表的形式
print(query_dict) # <QueryDict: {'page': ['10'], 'age': ['1']}>
# query_dict.urlencode() 将所有的url拼接成字符串
print(query_dict.urlencode()) # page=10&age=1
query_dict._mutable = True
...
...
...
...
# 首页
# 往url中加入page变量
query_dict.setlist('page',[1])
first= '<li><a href="?{}">首页</a></li>'.format(query_dict.urlencode())
page_list.append(first)
# 上一页
if page > 1:
query_dict.setlist('page', [page-1])
prev = '<li><a href="?{}">上一页</a></li>'.format(query_dict.urlencode())
page_list.append(prev)
else:
query_dict.setlist('page', [page])
prev = '<li><a href="?{}">上一页</a></li>'.format(query_dict.urlencode())
page_list.append(prev)
# 可显示的页面区间
# i 表示页码
for i in range(page_start, page_end + 1):
# 当前页面选中效果
if i == page:
query_dict.setlist('page', [i])
li = '<li class="active"><a href="?{}">{}</a></li>'.format(query_dict.urlencode(), i)
else:
query_dict.setlist('page', [i])
li = '<li><a href="?{}">{}</a></li>'.format(query_dict.urlencode(), i)
page_list.append(li)
# 下一页
if page < page_count:
query_dict.setlist('page', [page+1])
next = '<li><a href="?{}">下一页</a></li>'.format(query_dict.urlencode())
page_list.append(next)
else:
query_dict.setlist('page', [page])
next = '<li><a href="?{}">下一页</a></li>'.format(query_dict.urlencode())
page_list.append(next)
# 尾页
query_dict.setlist('page', [page_count])
last = '<li><a href="?{}">尾页</a></li>'.format(query_dict.urlencode())
page_list.append(last)
# 跳转至
search_string = """
<li>
<form style="float: left;margin-left: -1px" method="get">
<input name="page"
style="position: relative;float:left;display: inline-block;width: 80px;border-radius: 0;"
type="text" class="form-control" placeholder="页码">
<button style="border-radius: 0" class="btn btn-default" type="submit">跳转</button>
</form>
</li>
"""
page_list.append(search_string)
page_str = mark_safe(''.join(page_list)) # 分页功能的标签(html渲染)
return render(request, "number_list.html", {"NumList": NumList, "mobile": mobile, "page_str": page_str})
2.3.3 将分页功能包装成分页类组件
- 分页类组件的创建
项目-app-utils-pagination.py
- 分页功能类的变量初始化
request: 请求的对象
queryset: 从数据库查出的符合条件的数据(要分页的数据)
page_size: 每页显示多少条数据
page_param: get请求从url中获取分页的参数
page_num_size:显示当前页的前后几页 (page_num_size*2+1为能显示的页码范围)
def __init__(self, request, queryset, page_size=10, page_param='page', page_num_size=5):
# copy.deepcopy(request.GET)返回url中所有拼接的变量
# 以字典的形式返回所有的url value以列表的形式
# <QueryDict: {'page': ['10'], 'age': ['1']}>
query_dict = copy.deepcopy(request.GET)
# query_dict.urlencode() 将所有的url拼接成字符串 page=10&age=1
query_dict._mutable = True
self.query_dict = query_dict
# 根据前端get请求获取page /number/list?page=xx page不存在时默认返回1
self.page_param = page_param
page = request.GET.get(page_param, '1') # 当前页码
# 判断前端get请求传来的page,确保为正整数
# 若为10进制数,则转化为int型,否则默认返回首页
if page.isdecimal():
page = int(page)
else:
page = 1
data_start = (page - 1) * page_size # 页面显示数据的起始位置
data_end = page * page_size # 页面显示数据的末位置
self.page = page
self.page_size = page_size
self.page_num_size = page_num_size
self.data_start = data_start
self.data_end = data_end
self.query_set = queryset[self.data_start:self.data_end] # 数据进行分页(每页的数据)
data_count = queryset.count() # 从数据库查出的符合条件的数据(要分页的数据)个数
page_count = int(data_count / page_size) + 1 # 页面个数
self.page_count = page_count
self.page_num_size = page_num_size # 显示当前页的前后几页
- 创建分页功能页面标签
def createHtml(self):
"""分页功能"""
'''在此生成分页标签page_str
<li><a href="?page=1">1</a></li>
<li><a href="?page=2">2</a></li>
<li><a href="?page=3">3</a></li>
<li><a href="?page=4">4</a></li>
<li><a href="?page=5">5</a></li>
'''
# 数据较少,总页面没有达到11页
if self.page_count <= 2 * self.page_num_size + 1:
page_start = 1
page_end = self.page_count
else:
if self.page <= self.page_num_size:
page_start = 1
page_end = self.page_num_size * 2 + 1
else:
if self.page + self.page_num_size >= self.page_count:
page_start = self.page_count - self.page_num_size * 2
page_end = self.page_count
else:
page_start = self.page - self.page_num_size
page_end = self.page + self.page_num_size
page_list = []
# 首页
# 往url中加入page变量
self.query_dict.setlist('page', [1])
first = '<li><a href="?{}">首页</a></li>'.format(self.query_dict.urlencode())
page_list.append(first)
# 上一页
if self.page > 1:
self.query_dict.setlist('page', [self.page - 1])
prev = '<li><a href="?{}">上一页</a></li>'.format(self.query_dict.urlencode())
page_list.append(prev)
else:
self.query_dict.setlist('page', [self.page])
prev = '<li><a href="?{}">上一页</a></li>'.format(self.query_dict.urlencode())
page_list.append(prev)
# 可显示的页面区间
# i 表示页码
for i in range(page_start, page_end + 1):
# 当前页面选中效果
if i == self.page:
self.query_dict.setlist('page', [i])
li = '<li class="active"><a href="list?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
else:
self.query_dict.setlist('page', [i])
li = '<li><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
page_list.append(li)
# 下一页
if self.page < self.page_count:
self.query_dict.setlist('page', [self.page + 1])
next = '<li><a href="?{}">下一页</a></li>'.format(self.query_dict.urlencode())
page_list.append(next)
else:
self.query_dict.setlist('page', [self.page])
next = '<li><a href="?{}">下一页</a></li>'.format(self.query_dict.urlencode())
page_list.append(next)
# 尾页
self.query_dict.setlist('page', [self.page_count])
last = '<li><a href="?{}">尾页</a></li>'.format(self.query_dict.urlencode())
page_list.append(last)
# 跳转至
search_string = """
<li>
<form style="float: left;margin-left: -1px" method="get">
<input name="page"
style="position: relative;float:left;display: inline-block;width: 80px;border-radius: 0;"
type="text" class="form-control" placeholder="页码">
<button style="border-radius: 0" class="btn btn-default" type="submit">跳转</button>
</form>
</li>
"""
page_list.append(search_string)
page_str = mark_safe(''.join(page_list)) # 分页功能的标签(html渲染)
return page_str
2.3.4 组件的使用
自定义的分页组件,以后如果想要使用这个分页组件,你需要做如下几件事:
在视图函数中:
def pretty_list(request): # 1.根据自己的情况去筛选自己的数据(即需要分页的数据) queryset = models.PrettyNum.objects.all() # 2.实例化分页对象 page_object = Pagination(request, queryset) ############################### 重要 ########################################## context = { # "queryset": page_object.page_queryset, # 每页待展示的数据(每页的数据) # "page_string": page_object.html() # 生成页码的html标签字符 # } # ############################################################################## return render(request, 'pretty_list.html', context)
在HTML页面中
- 展示数据
{% for obj in queryset %} {{obj.xx}} {% endfor %}
- 分页功能的html标签
<ul class="pagination"> {{ page_string }} </ul>
实例应用
- 展示视图函数
def number_list(request):
# 利用get获取搜索条件
data_dict = {}
mobile = request.GET.get('mobile', "")
if mobile:
# {关键字: 范围, }
data_dict['mobile__contains'] = mobile
# date_dict为空时,全部查找 不为空按条件查找
# 数据库查询数据
NumList = models.PrettyNum.objects.filter(**data_dict).order_by("-level") # 带分页的数据列表
# 调用分页组件 创建分页的对象
page_object = Pagination(request,NumList)
context = {
"NumList": page_object.query_set, # 每页的待展示的数据
"mobile": mobile,
"page_str": page_object.createHtml() # 分页功能的标签(html渲染)按钮
}
return render(request, "number_list.html", context)
- html页面
{% extends 'layout.html' %}
{% block content %}
<div style="margin-bottom: 10px">
<a type="button" class="btn btn-success" href="/number/add"><span class="glyphicon glyphicon-plus-sign"
aria-hidden="true"></span> 添加靓号</a>
<div style="width: 300px; float: right">
<form method="get" action="/number/list">
<div class="input-group">
<input type="text" class="form-control" name="mobile" placeholder="Search for..."
value="{{ mobile }}">
<span class="input-group-btn">
<button class="btn btn-default" type="submit"><span class="glyphicon glyphicon-search"
aria-hidden="true"></span></button>
</span>
</div>
</form>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">靓号列表</div>
<div class="bs-example" data-example-id="hoverable-table">
<table class="table table-hover">
<thead>
<tr>
<th>ID</th>
<th>号码</th>
<th>价格</th>
<th>级别</th>
<th>状态</th>
</tr>
</thead>
<tbody>
{% for number in NumList %}
<tr>
<td>{{ number.id }}</td>
<td>{{ number.mobile }}</td>
<td>{{ number.price }}</td>
{# choice 类型采用get_xxx_display 方式获取 #}
<td>{{ number.get_level_display }}</td>
<td>{{ number.get_status_display }}</td>
<td>
<a class="btn btn-warning btn-sm" href="/number/{{ number.id }}/update">编辑</a>
<a class="btn btn-danger btn-sm" href="/number/del?nid={{ number.id }}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<ul class="pagination">
{{ page_str }}
</ul>
</div>
{% endblock %}
3.靓号的添加操作
number_add.html
{% extends 'layout.html' %}
{% block content %}
<div class="panel panel-default">
<div class="panel-heading">靓号添加</div>
<div class="panel-body">
<div class="bs-example" data-example-id="simple-form-inline">
<form class="form" method="post" action="/number/add" novalidate>
{% csrf_token %}
{#创建表单,form为userinfo各字段的表单#}
{#每一个field都是一个字段的输入框#}
{% for field in form %}
<div class="form-group">
<label>{{ field.label }}</label>
{{ field }}
<span style="color: red">{{ field.errors.0 }}</span>
{#field.errors.0显示第一条错误即可#}
</div>
{% endfor %}
<input type="submit" class="btn btn-success" value="提交">
</form>
</div>
</div>
</div>
{% endblock %}
views.py
class number_ModelForm(forms.ModelForm):
class Meta:
model = models.PrettyNum
fields = ['mobile', 'price', 'level', 'status']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for key, value in self.fields.items():
value.widget.attrs = {'class': 'form-control', "placeholder": value.label}
# 校验方式2:钩子方法
def clean_mobile(self):
# txt_mobile 表示用户输入的数据,即待校验数据
txt_mobile = self.cleaned_data['mobile']
# 判断是否满足校验规则
# ① 手机号格式 re.search(r'^\d{11}$', txt_mobile)
# ② 手机号不能重复 flag = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()
flag = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()
# 以下 判断出自己以外的mobile是否存在
# form = number_editModelForm(instance=row_date) 调用该类是传入instance(待操作的数据行);self.instance.pk(待操作的数据行的id)
# flag = models.PrettyNum.objects.exclude(id=self.instance.pk).filter(mobile=txt_mobile).exists()
if (re.match(r'^\d{11}$', txt_mobile)) and not flag:
# 校验通过,返回输入数据
return txt_mobile
elif not re.match(r'^\d{11}$', txt_mobile):
raise ValidationError("格式错误")
else:
raise ValidationError("手机号已存在")
def number_add(request):
"""靓号添加"""
if request.method == "GET":
# 创建number_ModelForm的表单对象,返回值为一个表单
form = number_ModelForm()
print(form)
return render(request, "number_add.html", {'form': form})
form = number_ModelForm(request.POST)
if form.is_valid():
form.save()
return redirect('/number/list')
return render(request, 'number_add.html', {'form': form})
3.1 校验的两种方法
3.1.1 正则表达式方法
# 校验方式1:利用正则表达式增加手机号有效规则
mobile = forms.CharField(
label='手机号',
validators=[RegexValidator(r'^\d{11}$', '手机格式错误'), ]
)
方法一:利用正则表达式重新定义mobile字段
validators验证器 r'^\d{11}$' 11位数字 r 表示原生字符串(rawstring),该字符串声明了引号中的内容表示该内容的原始含义,避免了多次转义造成的反斜杠困扰。
3.1.2钩子函数
# 校验方式2:钩子方法
def clean_mobile(self):
# txt_mobile 表示用户输入的数据,即待校验数据
txt_mobile = self.cleaned_data['mobile']
# 判断是否满足校验规则
# ① 手机号格式 re.search(r'^\d{11}$', txt_mobile)
# ② 手机号不能重复 flag = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()
flag = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()
# 以下 判断出自己以外的mobile是否存在
# form = number_editModelForm(instance=row_date) 调用该类是传入instance(待操作的数据行);self.instance.pk(待操作的数据行的id)
# flag = models.PrettyNum.objects.exclude(id=self.instance.pk).filter(mobile=txt_mobile).exists()
if (re.match(r'^\d{11}$', txt_mobile)) and not flag:
# 校验通过,返回输入数据
return txt_mobile
elif not re.match(r'^\d{11}$', txt_mobile):
raise ValidationError("格式错误")
else:
raise ValidationError("手机号已存在")
方法二:钩子函数
- txt_mobile 表示用户输入的数据,即待校验数据
txt_mobile = self.cleaned_data['mobile']
- 判断是否满足校验规则
① 手机号格式
re.search(r'^\d{11}$', txt_mobile)
re.match(r'^\d{11}$', txt_mobile)
② 手机号不能重复
flag = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()
- 判断除自己以外的mobile是否存在(除去自己的mobile是否还有和自己一样的mobile)
flag = models.PrettyNum.objects.exclude(id=self.instance.pk).filter(mobile=txt_mobile).exists()
self.instance.pk
能获取待操作的数据行的id
3.2 时间插件
<link rel="stylesheet" href="static/plugins/bootstrap-3.4.1/css/bootstrap.css">
<link rel="stylesheet" href="static/plugins/bootstrap-datepicker/css/bootstrap-datepicker.css">
<input type="text" id="dt" class="form-control" placeholder="入职日期">
<script src="static/js/jquery-3.6.0.min.js"></script>
<script src="static/plugins/bootstrap-3.4.1/js/bootstrap.js"></script>
<script src="static/plugins/bootstrap-datepicker/js/bootstrap-datepicker.js"></script>
<script src="static/plugins/bootstrap-datepicker/locales/bootstrap-datepicker.zh-CN.min.js"></script>
<script>
$(function () {
$('#dt').datepicker({ //#id 日期选择器应用输入框的id
format: 'yyyy-mm-dd', // 显示格式
//startDate: '0', /日期选择的起始时间为目前时间,若想选择以前的时间注释掉
language: "zh-CN",
autoclose: true //选择完日期,时间框自动消失
});
})
</script>
4.靓号的更新操作
number_update.html
{% extends 'layout.html' %}
{% block content %}
<div class="panel panel-default">
<div class="panel-heading">号码编辑</div>
<div class="panel-body">
<div class="bs-example" data-example-id="simple-form-inline">
<form class="form" method="post" action="/number/{{ nid }}/update" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label>{{ field.label }}</label>
{{ field }}
<span style="color: red">{{ field.errors.0 }}</span>
{# field.errors.0显示第一条错误即可 #}
</div>
{% endfor %}
<input type="submit" class="btn btn-success" value="提交">
</form>
</div>
</div>
</div>
{% endblock %}
views.py
class number_editModelForm(forms.ModelForm):
# 校验方式1:利用正则表达式增加手机号有效规则
mobile = forms.CharField(
disabled=True, # 更新时,新增手机号无法修改规则
label='手机号',
# validators验证器
# r'^\d{11}$' 11位数字
# r 表示原生字符串(rawstring),该字符串声明了引号中的内容表示该内容的原始含义,避免了多次转义造成的反斜杠困扰。
validators=[RegexValidator(r'^\d{11}$', '手机格式错误'), ]
)
class Meta:
model = models.PrettyNum
fields = ['mobile', 'price', 'level', 'status']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for key, value in self.fields.items():
value.widget.attrs = {'class': 'form-control', "placeholder": value.label}
def number_update(request, nid):
row_date = models.PrettyNum.objects.filter(id=nid).first()
if request.method == "GET":
form = number_editModelForm(instance=row_date)
return render(request, 'number_update.html', {'form': form, 'nid': nid})
form = number_editModelForm(data=request.POST, instance=row_date)
if form.is_valid():
form.save()
return redirect('/number/list')
return render(request, 'number_update.html', {'form': form, 'nid': nid})
- 利用正则表达式增加手机号有效规则
``` mobile = forms.CharField( disabled=True, # 更新时,新增手机号无法修改规则 label='手机号', validators验证器 r'^\d{11}$' 11位数字 r 表示原生字符串(rawstring),该字符串声明了引号中的内容表示该内容的原始含义,避免了多次转义造成的反斜杠困扰。 validators=[RegexValidator(r'^\d{11}$', '手机格式错误'), ] ) ``` **新增规则:** disabled=True, # 更新时,新增一个手机号无法修改的规则 **更新获取id的url格式:**`http://localhost:8000/number/nid/update`
5.靓号的删除操作
views.py
def number_del(request):
# http://localhost:8000/number/del?nid=xx
# get形式获取id
nid = request.GET.get('nid')
models.PrettyNum.objects.filter(id=nid).delete()
return redirect('/number/list')
6.项目文件的整合
同类文件提取,然后合并一个新文件中
切勿忘记引入
6.1 对ModelForm增加样式的BootStrap整合
以自定义初始函数的方式为例
项目-app-utils-bootstrap.py
- 提取ModelForm类中自定义初始函数
- 自定义ModelForm类时对BootStrapModelForm类进行继承
bootstrap.py
class BootStrapModelForm_user(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有的插件,添加了class="form-control"
for key, value in self.fields.items():
# 加样式
if key == "creat_time":
# python中当前时间并且格式化形式datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# django模板语言当前时间并且格式形式 {% now 'Y-m-d' %} 或 {{ user.creat_time|date:"Y-m-d" }}
value.widget.attrs = {"class": "form-control", "placeholder": value.label,
"value": datetime.datetime.now().strftime("%Y-%m-%d"),
"id": "dt_creat_time"}
else:
value.widget.attrs = {"class": "form-control", "placeholder": value.label}
class BootStrapModelForm_number(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for key, value in self.fields.items():
value.widget.attrs = {'class': 'form-control', "placeholder": value.label}
6.2定义ModelForm类的整合
项目-app-utils-form.py
form.py
class user_ModelForm(BootStrapModelForm_user):
password = forms.CharField(min_length=6, label="密码")
class Meta:
model = models.UserInf
fields = ['name', 'password', 'age', 'account', 'creat_time', 'gender', 'depart']
class number_ModelForm(BootStrapModelForm_number):
class Meta:
model = models.PrettyNum
fields = ['mobile', 'price', 'level', 'status']
def clean_mobile(self):
txt_mobile = self.cleaned_data['mobile']
flag = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()
if (re.match(r'^\d{11}$', txt_mobile)) and not flag:
return txt_mobile
elif not re.match(r'^\d{11}$', txt_mobile):
raise ValidationError("格式错误")
else:
raise ValidationError("手机号已存在")
class number_editModelForm(BootStrapModelForm_number):
mobile = forms.CharField(
disabled=True,
label='手机号',
validators=[RegexValidator(r'^\d{11}$', '手机格式错误'), ]
)
class Meta:
model = models.PrettyNum
fields = ['mobile', 'price', 'level', 'status']
6.3对views视图函数的整合
- 各视图函数进行归类划分将对应函数转移到对应的文件中,文件位置在
项目-app-views-xxx.py
- 部门管理
将对应函数转移到对应的文件中
depart.py
from django.shortcuts import render, redirect
from app01 import models
def depart_list(request):
""" 部门列表 """
'''获取数据部门信息'''
depart_list = models.Department.objects.all()
return render(request, "depart_list.html", {"depart_list": depart_list})
def depart_add(request):
""" 部门添加 """
if request.method == 'GET':
return render(request, "depart_add.html")
title = request.POST.get("title")
models.Department.objects.create(title=title)
return redirect('/depart/list')
def depart_del(request):
"""部门删除"""
# http://localhost:8000/depart/del?nid=id
nid = request.GET.get("nid")
models.Department.objects.filter(id=nid).delete()
return redirect('/depart/list')
def depart_update(request, nid):
# http://localhost:8000/depart/nid/update
"""部门编辑"""
if request.method == 'GET':
dept = models.Department.objects.filter(id=nid).get()
return render(request, "depart_update.html", {"dept": dept})
title = request.POST.get("title")
models.Department.objects.filter(id=nid).update(title=title)
return redirect('/depart/list')
- 员工管理
将对应函数转移到对应的文件中
user.py
from django.shortcuts import render, redirect
from app01.utils.form import user_ModelForm
from app01 import models
def user_list(request):
'''获取用户信息'''
user_list = models.UserInfo.objects.all()
# print(user_list)
return render(request, "user_list.html", {"user_list": user_list})
def user_add(request):
'''新增员工'''
if request.method == 'GET':
context = {
"depart_list": models.Department.objects.all(),
"gender_list": models.UserInfo.gender_choice,
}
return render(request, "user_add.html", context)
# 缺少数据校验和错误提示
# 前端的每一个字段都得写一遍
# 关联的数据,需要手动获取并循环展示
name = request.POST.get("name")
password = request.POST.get("pwd")
age = request.POST.get("age")
account = request.POST.get("account")
creat_time = request.POST.get("creat_time")
gender = request.POST.get("gender")
depart_id = request.POST.get("depart")
models.UserInfo.objects.create(name=name, password=password, age=age, account=account, creat_time=creat_time,
gender=gender, depart_id=depart_id)
return redirect('/user/list')
###################################################################
def user_ModelForm_add(request):
if request.method == 'GET':
# form为userinfo各字段的表单
form = user_ModelForm()
# print(form)
return render(request, "user_ModelForm_add.html", {"form": form})
# 将前端表单的post请求,直接传入form对象中
form = user_ModelForm(request.POST)
# 判断数据是否合法有效(校验规则————models中建表表项规则 + class user_ModelForm(forms.ModelForm)重新定义表项规则)
if form.is_valid():
# 将表单保存到数据库中 1111
form.save()
return redirect('/user/list')
# 校验失败(在页面显示错误信息) form.error()含有错误
return render(request, "user_ModelForm_add.html", {"form": form})
def user_del(request):
""" 员工删除"""
nid = request.GET.get("nid")
models.UserInfo.objects.filter(id=nid).delete()
return redirect("/user/list")
def user_update(request, nid):
"""员工更新"""
if request.method == "GET":
context = {
"depart_list": models.Department.objects.all(),
"gender_list": models.UserInfo.gender_choice,
"user": models.UserInfo.objects.get(id=nid),
}
return render(request, "user_update.html", context)
name = request.POST.get("name")
password = request.POST.get("pwd")
age = request.POST.get("age")
account = request.POST.get("account")
creat_time = request.POST.get("creat_time")
gender = request.POST.get("gender")
depart_id = request.POST.get("depart")
models.UserInfo.objects.filter(id=nid).update(name=name, password=password, age=age, account=account,
creat_time=creat_time, gender=gender, depart_id=depart_id)
return redirect("/user/list")
def user_ModelForm_update(request, nid):
""" 编辑用户 """
# 根据nid取数据库获取要编辑的哪一行数据(行对象)
row_user = models.UserInfo.objects.filter(id=nid).first()
if request.method == "GET":
# form为userinfo各字段的表单
# instance=row_user并将row_user中各字段的数据赋值给form中各字段的值
form = user_ModelForm(instance=row_user)
return render(request, "user_ModelForm_update.html", {"form": form, "nid": nid})
# 将前端表单的post请求,直接传入form对象中
# 接收从前端传来的数据,并且在row_user的基础上保存在数据库 instance=row_user替换待修改的那一行数据,而不是新增
form = user_ModelForm(data=request.POST, instance=row_user)
print(form)
# 判断数据是否合法有效(校验规则————models中建表表项规则 + class user_ModelForm(forms.ModelForm)重新定义表项规则)
if form.is_valid():
# 将表单保存到数据库中
form.save()
return redirect('/user/list')
# 校验失败(在页面显示错误信息) form.error()含有错误
return render(request, "user_ModelForm_update.html", {"form": form, "nid": nid})
- 靓号管理
将对应函数转移到对应的文件中
number.py
from django.shortcuts import render, redirect
from app01.utils.form import number_ModelForm,number_editModelForm
from app01.utils.pagination import Pagination
from app01 import models
def number_list(request):
""" 靓号列表 """
# 良好等级高低展示
"""
order_by("level") 按照level正向排序 由低到高
order_by("-level") 按照level逆向排序 由高到低
"""
""" 条件显示列表
# 方式1 直接传
models.PrettyNum.objects.filter(mobile='15588886666', id=2)
# 方式2 传字典{关键字:范围,}
data_dict = {'mobile': '15588886666', 'id': 2}
models.PrettyNum.objects.filter(**data_dict)
"""
"""
django中常见的条件
models.PrettyNum.objects.filter(id=2, mobile="15666662222") # id等于2且 mobile="15666662222"
models.PrettyNum.objects.filter(id__gt=2, mobile__startswith="198") # id大于2 且 mobile以198开头
models.PrettyNum.objects.filter(id__gte=2, mobile__endswith="999") # id大于等于2且 mobile以999结尾
models.PrettyNum.objects.filter(id__lt=2, mobile__contains="888") # id小于2且 mobile包含888
models.PrettyNum.objects.filter(id__lte=2) # id小于等于2
"""
# 利用get获取搜索条件
data_dict = {}
mobile = request.GET.get('mobile', "")
if mobile:
# {关键字: 范围, }
data_dict['mobile__contains'] = mobile
# date_dict为空时,全部查找 不为空按条件查找
# 数据库查询数据
NumList = models.PrettyNum.objects.filter(**data_dict).order_by("-level") # 带分页的数据列表
# 调用分页组件 创建分页的对象
page_object = Pagination(request, NumList)
context = {
"NumList": page_object.query_set, # 每页的待展示的数据
"mobile": mobile,
"page_str": page_object.createHtml() # 分页功能的标签(html渲染)按钮
}
return render(request, "number_list.html", context)
def number_add(request):
"""靓号添加"""
if request.method == "GET":
# 创建number_ModelForm的表单对象,返回值为一个表单
form = number_ModelForm()
print(form)
return render(request, "number_add.html", {'form': form})
form = number_ModelForm(request.POST)
if form.is_valid():
form.save()
return redirect('/number/list')
return render(request, 'number_add.html', {'form': form})
def number_update(request, nid):
row_date = models.PrettyNum.objects.filter(id=nid).first()
if request.method == "GET":
form = number_editModelForm(instance=row_date)
return render(request, 'number_update.html', {'form': form, 'nid': nid})
form = number_editModelForm(data=request.POST, instance=row_date)
if form.is_valid():
form.save()
return redirect('/number/list')
return render(request, 'number_update.html', {'form': form, 'nid': nid})
def number_del(request):
# http://localhost:8000/number/del?nid=xx
# get形式获取id
nid = request.GET.get('nid')
models.PrettyNum.objects.filter(id=nid).delete()
return redirect('/number/list')
- 删除views.py
- 修改对应urls.py
from django.urls import path
from app01.views import depart,user,number
urlpatterns = [
#path('admin/', admin.site.urls),
# 部门管理
path('depart/list', depart.depart_list),
path('depart/add', depart.depart_add),
path('depart/del', depart.depart_del),
path('depart/<int:nid>/update', depart.depart_update),
# 用户管理
path('user/list', user.user_list),
path('user/add', user.user_add),
path('user/ModelForm/add', user.user_ModelForm_add),
path('user/del', user.user_del),
path('user/<int:nid>/update', user.user_update),
path('user/ModelForm/<int:nid>/update', user.user_ModelForm_update),
# 靓号管理
path('number/list',number.number_list),
path('number/add',number.number_add),
path('number/<int:nid>/update',number.number_update),
path('number/del',number.number_del),
]