靓号管理
表结构
修改myproject/employee_management/models.py
class PrettyNum(models.Model):
"""靓号表"""
# 如果想要为空 null=True blank=True
mobile = models.CharField(verbose_name="手机号", max_length=32)
price = models.IntegerField(verbose_name="价格", default=0)
level_choices = (
(1, "1级"),
(2, "2级"),
(3, "3级"),
(4, "4级"),
)
level = models.SmallIntegerField(verbose_name="级别", choices=level_choices, default=1)
status_choices = (
(1, "已占用"),
(2, "未使用"),
)
status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=2)
生成数据库表
python3 manage.py makemigrations
python3 manage.py migrate
手动模拟添加一些数据
insert into employee_management_prettynum(mobile, price, level, status) values("15811223344", 500, 2, 2);
insert into employee_management_prettynum(mobile, price, level, status) values("13846783361", 100, 3, 2);
靓号列表
相信到这里大家可以做到这里,可以说是已经轻车熟路了
修改myproject/employee_management/views.py
增加pretty_list
函数
def pretty_list(request):
"""靓号列表"""
# select * from 表 by level desc;
pretty_data = PrettyNum.objects.all().order_by("-level")
return render(request, "pretty_list.html", {"pretty_data": pretty_data})
修改myproject/myproject/urls.py
path('pretty/list/', views.pretty_list),
新建myproject/employee_management/templates/pretty_list.html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div style="margin-bottom: 10px">
<a class="btn btn-primary" href="/user/model/form/add/" target="_blank">新建靓号</a>
</div>
<div>
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true" style="margin-right: 5px;"></span>
<span>靓号列表</span>
</div>
<!-- Table -->
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>号码</th>
<th>价格</th>
<th>级别</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in pretty_data %}
<tr>
<th>{{ obj.id }}</th>
<td>{{ obj.mobile }}</td>
<td>{{ obj.price }}</td>
<td>{{ obj.get_level_display }}</td>
<td>{{ obj.get_status_display }}</td>
<td>
<a class="btn btn-primary btn-xs" href="/user/{{ obj.id }}/edit/">编辑</a>
<a class="btn btn-danger btn-xs" href="/user/{{ obj.id }}/delete/">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
运行,浏览器访问测试
这里在导航栏中增加一个”靓号管理”的标签
修改myproject/employee_management/templates/layout.html
<li><a href="/pretty/list/">靓号管理</a></li>
靓号添加
修改myproject/employee_management/views.py
from django.core.validators import RegexValidator
class PrettyModelForm(forms.ModelForm):
# 数据校验
mobile = forms.CharField(
label="手机号",
validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'),],
)
class Meta:
model = PrettyNum
# fields = "__all__" 表示取表中所有的字段
fields = ['mobile', 'price', 'level', 'status']
# exclude = ['level'] 表示取除了表中的某个字段的所有字段
# 循环找到所有的插件,加入css样式,添加 "class": "form-control"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
print(name, field)
field.widget.attrs = {"class": "form-control"}
def pretty_add(request):
"""添加靓号"""
if request.method == "GET":
form = PrettyModelForm()
return render(request, "pretty_add.html", {"form": form})
# 用户POST请求提交数据,需要进行数据校验
form = PrettyModelForm(data=request.POST)
if form.is_valid():
print(form.cleaned_data)
# 直接保存至数据库
form.save()
return redirect("/pretty/list/")
# 校验失败(在页面上显示错误信息)
return render(request, "pretty_add.html", {"form": form})
修改/root/python/myproject/myproject/urls.py
path('pretty/add/', views.pretty_add),
修改myproject/employee_management/templates/pretty_list.html
修改 href
<a class="btn btn-primary" href="/pretty/add/" target="_blank">新建靓号</a>
新建myproject/employee_management/templates/pretty_add.html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">添加靓号</h3>
</div>
<div class="panel-body">
<form action="/pretty/add/" method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label>{{ field.label }}: </label>
{{ field }}
<!-- 数据校验,显示错误信息 -->
<span style="color: red;">{{ field.errors.0 }}</span>
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">保存</button>
</form>
</div>
</div>
</div>
{% endblock %}
</body>
</html>
浏览器访问测试
格式只能11位手机号
点击保存
数据校验的方式还有另外一种,更为复杂的
修改myproject/employee_management/views.py
from django.core.exceptions import ValidationError
class PrettyModelForm(forms.ModelForm):
# 此处省略中间内容
...
# 数据校验: 验证方式2
def clean_mobile(self):
txt_mobile = self.cleaned_data['mobile']
if len(txt_mobile) != 11:
# 验证不通过
raise ValidationError('格式错误')
# 验证通过
return txt_mobile
同样的效果,选择其中一种方式即可
靓号编辑
重新复习一下编辑实现的逻辑:
- 列表页面点击”编辑”按钮
- 匹配
urls.py
中的定义的pathviews.py
中定义的函数接收到POST请求提交的nid
- 函数根据
nid
找到对应的数据行templates
模板下的HTML文件根据Django的方法展示数据
修改myproject/employee_management/views.py
def pretty_edit(request, nid):
"""编辑靓号"""
row_obj = PrettyNum.objects.filter(id=nid).first()
# GET请求
if request.method == "GET":
form = PrettyModelForm(instance=row_obj)
return render(request, "pretty_edit.html", {"form": form})
# POST请求
form = PrettyModelForm(data=request.POST, instance=row_obj)
if form.is_valid():
form.save()
return redirect("/pretty/list/")
return render(request, "pretty_edit.html", {"form": form})
修改myproject/myproject/urls.py
path('pretty/<int:nid>/edit/', views.pretty_edit),
新建/root/python/myproject/employee_management/templates/pretty_edit.html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">编辑靓号</h3>
</div>
<div class="panel-body">
<form method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label>{{ field.label }}: </label>
{{ field }}
<!-- 数据校验,显示错误信息 -->
<span style="color: red;">{{ field.errors.0 }}</span>
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">保存</button>
</form>
</div>
</div>
</div>
{% endblock %}
</body>
</html>
修改/root/python/myproject/employee_management/templates/pretty_list.html
浏览器点击”编辑”更改数据测试即可
现在有一个新的需求,不想让用户编辑手机号字段,该怎么做?
其实我们可以单独新增一个class,去掉mobile
字段
修改myproject/employee_management/views.py
class PrettyEditModelForm(forms.ModelForm):
class Meta:
model = PrettyNum
# fields = "__all__" 表示取表中所有的字段
fields = ['price', 'level', 'status']
# exclude = ['level'] 表示取除了表中的某个字段的所有字段
# 循环找到所有的插件,加入css样式,添加 "class": "form-control"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
print(name, field)
field.widget.attrs = {"class": "form-control"}
def pretty_edit(request, nid):
"""编辑靓号"""
row_obj = PrettyNum.objects.filter(id=nid).first()
# GET请求
if request.method == "GET":
form = PrettyEditModelForm(instance=row_obj)
return render(request, "pretty_edit.html", {"form": form})
# POST请求
form = PrettyEditModelForm(data=request.POST, instance=row_obj)
if form.is_valid():
form.save()
return redirect("/pretty/list/")
return render(request, "pretty_edit.html", {"form": form})
浏览器访问,可以发现没有手机号了
这时可能有人会说,我就是想要加上手机号字段,但是不想让他可编辑
这个当然也可以实现哈
修改myproject/employee_management/views.py
mobile = forms.CharField(disabled=True, label="手机号")
浏览器刷新
那如果也允许编辑手机号字段呢
那么这样会有一个问题,如果手机号已经存在怎么办?
这里就涉及到了手机号的重复性问题
不允许手机号重复
- 添加: 如果手机号已存在,提示”手机号已存在”
- 编辑: 如果手机号除了当前手机号以外已存在,提示”手机号已存在”
添加和编辑的逻辑不太一样,编辑需要将它自己先排除然后再做判断
首先实现”添加”功能的手机号重复验证
修改myproject/employee_management/views.py
中class PrettyModelForm
的clean_mobile
函数
# 数据校验: 验证方式2
def clean_mobile(self):
txt_mobile = self.cleaned_data['mobile']
if len(txt_mobile) != 11:
# 验证不通过
raise ValidationError('格式错误')
exists_data = PrettyNum.objects.filter(mobile=txt_mobile).exists()
if exists_data:
raise ValidationError("手机号已存在")
# 验证通过
return txt_mobile
浏览器访问测试
实现”编辑”功能的手机号重复验证
注意: 下面修改的是
PrettyEditModelForm
类下面的函数
修改myproject/employee_management/views.py
中class PrettyEditModelForm
的clean_mobile
函数
# 数据校验: 验证方式2
def clean_mobile(self):
txt_mobile = self.cleaned_data['mobile']
if len(txt_mobile) != 11:
# 验证不通过
raise ValidationError('格式错误')
# exclude 表示排除哪一个数据
# self.instance.pk 表示当前编辑的哪一行 id
exists_data = PrettyNum.objects.exclude(id=self.instance.pk).filter(mobile=txt_mobile).exists()
if exists_data:
raise ValidationError("手机号已存在")
# 验证通过
return txt_mobile
不更改直接保存,正常
将手机号更改为已经存在的其他电话号码,保存,则提示”手机号已存在”
靓号删除
修改myproject/employee_management/views.py
def pretty_delete(request, nid):
"""删除靓号"""
PrettyNum.objects.filter(id=nid).delete()
return redirect('/pretty/list/')
修改myproject/myproject/urls.py
path('pretty/<int:nid>/delete/', views.pretty_delete),
修改/root/python/myproject/employee_management/templates/pretty_list.html
浏览器测试即可
手机号搜索
query1 = PrettyNum.objects.filter(mobile=15576547933, id=4)
print(query1)
# 如果是空字典,表示获取所有
query_dict = {"mobile": "15576547933", "id": 4}
query2 = PrettyNum.objects.filter(**query_dict)
print(query2)
PrettyNum.objects.filter(id=4) # 等于4
PrettyNum.objects.filter(id__gt=4) # 大于4
PrettyNum.objects.filter(id__gte=4) # 大于等于4
PrettyNum.objects.filter(id__lt=4) # 小于4
PrettyNum.objects.filter(id__lte=4) # 小于等于4
PrettyNum.objects.filter(mobile__startswith="1999") # 筛选出以"1999"开头的
PrettyNum.objects.filter(mobile__endswith="1999") # 筛选出以"1999"结尾的
PrettyNum.objects.filter(mobile__contains="1999") # 筛选出包含"1999"开头的
接下来我们来实现这个功能
修改myproject/employee_management/views.py
def pretty_list(request):
"""靓号列表"""
data_dict = {}
search_data = request.GET.get('query', "") # 不加后面的 "", 首次访问浏览器,搜索框中不会显示前端页面中的 placeholder="Search for..." 属性
if search_data:
# mobile_contains 表示筛选出字段 mobile 包含 search_data 数据的行
data_dict["mobile__contains"] = search_data
# select * from 表 by level desc;
# data_dict 如果是空字典,表示获取所有
pretty_data = PrettyNum.objects.filter(**data_dict).order_by("-level")
# 加入search_data的目的是,当搜索后,搜索框内的值不会置为空
return render(request, "pretty_list.html", {"pretty_data": pretty_data, "search_data": search_data})
修改myproject/employee_management/templates/pretty_list.html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div>
<div style="margin-bottom: 10px; ">
<a class="btn btn-primary" href="/pretty/add/" target="_blank">新建靓号</a>
<div style="float: right; width: 300px;">
<form method="get">
<div class="input-group">
<input type="text" name="query" class="form-control" placeholder="Search for..."
value="{{ search_data }}">
<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>
<div>
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true" style="margin-right: 5px;"></span>
<span>靓号列表</span>
</div>
<!-- Table -->
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>号码</th>
<th>价格</th>
<th>级别</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in pretty_data %}
<tr>
<th>{{ obj.id }}</th>
<td>{{ obj.mobile }}</td>
<td>{{ obj.price }}</td>
<td>{{ obj.get_level_display }}</td>
<td>{{ obj.get_status_display }}</td>
<td>
<a class="btn btn-primary btn-xs" href="/pretty/{{ obj.id }}/edit/">编辑</a>
<a class="btn btn-danger btn-xs" href="/pretty/{{ obj.id }}/delete/">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
浏览器访问测试
进行搜索
分页
quertset = PrettyNum.objects.filter(id=1)[0:10]
quertset = PrettyNum.objects.all()[0:10] # 取0到10行数据
先使用最原始的代码方式实现分页
内容较多,仔细看,有很多的细节
修改myproject/employee_management/views.py
from django.utils.safestring import mark_safe
def pretty_list(request):
"""靓号列表"""
################### 纯代码实现分页 ###################
# 插入一些演示数据,使用完注释掉
# for i in range(300):
# PrettyNum.objects.create(mobile="13811223344", price=100, level=3, status=1)
page_now = int(request.GET.get('page', 1))
page_range = 5 # 当前页面前后留几个页码
start = (page_now - 1) * 10
end = page_now * 10 + 2
# 总数据行数
data_num = PrettyNum.objects.all().count()
# 总页码
page_num, div = divmod(data_num, 10)
if div:
page_num += 1
page_show = 5
# 如果总页码数量大于 11
if page_num > page_show * 2 + 1:
# 如果当前页面页码位置小于等于5
if page_now <= 5:
start_page = 1
end_page = page_show * 2 + 2
# 否则,当前页面页码位置大于5时
else:
# 防止页码超出范围
if page_now >= page_num - page_show:
start_page = page_num - page_show * 2
end_page = page_num + 1
else:
# 计算出当前页的前5页和后5页
start_page = page_now - page_show
end_page = page_now + page_show + 1
else:
start_page = 1
end_page = page_num + 1
######## 创建页码 ########
# 页码
page_str_list = []
# 跳到首页
head_page = '?page={}'.format(1)
# 跳到上10页
# 如果当前页面小于 11, 防止超过最小页数
if page_now < page_show * 2 + 1:
prev = '<li><a href="?page={}">{}</a></li>'.format(1, "<<")
page_str_list.append(prev)
else:
prev = '<li><a href="?page={}">{}</a></li>'.format(page_now - 10, "<<")
page_str_list.append(prev)
for i in range(start_page, end_page):
# 如果是当前页,高亮显示页码颜色
if page_now == i:
ele = '<li class="active"><a href="?page={}">{}</a></li>'.format(i, i)
else:
ele = '<li><a href="?page={}">{}</a></li>'.format(i, i)
page_str_list.append(ele)
### 跳到下10页
# 如果当前页面页数 大于 最大页面数量减去(page_show*2+1),则直接跳到最后一页,防止超过最大页数
if page_now >= page_num - page_show * 2 + 1:
next = '<li><a href="?page={}">{}</a></li>'.format(page_num, ">>")
page_str_list.append(next)
else:
next = '<li><a href="?page={}">{}</a></li>'.format(page_now + 10, ">>")
page_str_list.append(next)
page_string = mark_safe("".join(page_str_list))
# 跳到尾页
end_page = '?page={}'.format(page_num)
################### 代码实现分页结束 ###################
data_dict = {}
# 如果是空字典,表示获取所有
search_data = request.GET.get('query', "") # 不加后面的 "", 首次访问浏览器,搜索框中不会显示前端页面中的 placeholder="Search for..." 属性
if search_data:
data_dict["mobile__contains"] = search_data
# select * from 表 by level desc;
pretty_data = PrettyNum.objects.filter(**data_dict).order_by("-level")[start:end]
return render(request, "pretty_list.html", {"pretty_data": pretty_data, "search_data": search_data, "page_string": page_string, "head_page": head_page, "end_page": end_page})
修改myproject/employee_management/templates/pretty_list.html
<ul class="pagination">
<li><a href="{{ head_page }}" aria-label="Previous"><span aria-hidden="true">首页</span></a></li>
{{ page_string }}
<li><a href="{{ end_page }}" aria-label="Next"><span aria-hidden="true">尾页</span></a></li>
</ul>
<br>
<form method="get">
<div style="display:inline-block; width: 150px;">
<div class="input-group">
<span> <input type="text" class="form-control" placeholder="请输入页码" name="page"></span>
<span class="input-group-btn">
<button class="btn btn-primary" type="submit">跳转</button>
</span>
</div>
</div>
</form>
封装分页
实现分页代码的封装,方便以后其他代码的调用
在myproject/employee_management
目录下新建utils
目录
在utils
下新建pagination.py
文件
"""
自定义的分页组件
"""
from django.utils.safestring import mark_safe
class Pagination(object):
def __init__(self, request, queryset, page_size=10, page_param="page", page_show=5):
"""
:param request: 请求的对象
:param queryset: 符合条件的数据(根据此数据进行分页处理)
:param page_size: 每页显示多少条数据
:param page_param: 获取在URL中传递的分页参数, 例如: /pretty/list/?page=21
:param page_show: 页码显示前几页后几页
"""
page = int(request.GET.get(page_param, 1))
# 如果不是整数
if type(page) != int:
# 强制让页码为1
page = 1
self.page = page
self.start = (page - 1) * page_size
self.end = page * page_size
# 每页展示的数据行数
self.page_queryset = queryset[self.start:self.end]
total_data_count = queryset.count() # 数据行数
total_page_count, div = divmod(total_data_count, page_size)
if div:
total_page_count += 1
self.total_page_count = total_page_count # 总页码数量
self.page_show = page_show # 当前页前后展示的页码数量
self.request = request
def html(self):
# 如果总页码数量大于 11
if self.total_page_count > self.page_show * 2 + 1:
# 如果当前页面页码位置小于等于5
if self.page <= 5:
start_page = 1
end_page = self.page_show * 2 + 2
# 否则,当前页面页码位置大于5时
else:
# 防止页码超出范围
if self.page >= self.total_page_count - self.page_show:
start_page = self.total_page_count - self.page_show * 2
end_page = self.total_page_count + 1
else:
# 计算出当前页的前5页和后5页
start_page = self.page - self.page_show
end_page = self.page + self.page_show + 1
else:
start_page = 1
end_page = self.total_page_count + 1
######## 创建页码 ########
# 页码
page_str_list = []
# 跳到首页
self.head_page = '?page={}'.format(1)
# 跳到上10页
# 如果当前页面小于 11, 防止超过最小页数
if self.page < self.page_show * 2 + 1:
prev = '<li><a href="?page={}">{}</a></li>'.format(1, "<<")
page_str_list.append(prev)
else:
prev = '<li><a href="?page={}">{}</a></li>'.format(self.page - 10, "<<")
page_str_list.append(prev)
for i in range(start_page, end_page):
# 如果是当前页,高亮显示页码颜色
if self.page == i:
ele = '<li class="active"><a href="?page={}">{}</a></li>'.format(i, i)
else:
ele = '<li><a href="?page={}">{}</a></li>'.format(i, i)
page_str_list.append(ele)
# 跳到下10页
# 如果当前页面页数 大于 最大页面数量减去(page_show*2+1),则直接跳到最后一页,防止超过最大页数
if self.page >= self.total_page_count - self.page_show * 2 + 1:
next = '<li><a href="?page={}">{}</a></li>'.format(self.total_page_count, ">>")
page_str_list.append(next)
else:
next = '<li><a href="?page={}">{}</a></li>'.format(self.page + 10, ">>")
page_str_list.append(next)
self.page_string = mark_safe("".join(page_str_list))
# 跳到尾页
self.end_page = '?page={}'.format(self.total_page_count)
修改myproject/employee_management/views.py
def pretty_list(request):
"""靓号列表"""
data_dict = {}
# 如果是空字典,表示获取所有
# 不加后面的 "", 首次访问浏览器,搜索框中不会显示前端页面中的 placeholder="Search for..." 属性
search_data = request.GET.get('query', "")
if search_data:
data_dict["mobile__contains"] = search_data
queryset = PrettyNum.objects.filter(**data_dict).order_by("-level")
### 引入封装的 Pagination 类并初始化
# 初始化
page_object = Pagination(request, queryset, page_size=10, page_param="page")
page_queryset = page_object.page_queryset
# 调用对象的html方法,生成页码
page_object.html()
page_string = page_object.page_string
head_page = page_object.head_page
end_page = page_object.end_page
context = {
"pretty_data": page_queryset, # 分页的数据
"search_data": search_data, # 搜索的内容
"page_string": page_string, # 页码
"head_page": head_page, # 首页
"end_page": end_page, # 尾页
}
return render(request, "pretty_list.html", context)
浏览器刷新访问,你会发现效果和之前一样
解决小BUG
当我们进行搜索后,可以展示出搜索的对应数据
但是如果此时我们进行翻页,搜索数据将清空,重新展示所有的数据
这样是不符合逻辑的
下面的代码对之前的代码进行了优化:
- 将首页和尾页加入到了
page_str_list
列表中,方便后续其他页面进行调用
修改myproject/employee_management/utils/pagination.py
"""
自定义的分页组件
"""
from django.utils.safestring import mark_safe
import copy
class Pagination(object):
def __init__(self, request, queryset, page_size=10, page_param="page", page_show=5):
"""
:param request: 请求的对象
:param queryset: 符合条件的数据(根据此数据进行分页处理)
:param page_size: 每页显示多少条数据
:param page_param: 获取在URL中传递的分页参数, 例如: /pretty/list/?page=21
:param page_show: 页码显示前几页后几页
"""
# 防止搜索出结果进行翻页时,URL参数没有了搜索参数
query_dict = copy.deepcopy(request.GET)
query_dict._mutable = True
self.query_dict = query_dict
self.page_param = page_param
page = int(request.GET.get(page_param, 1))
# 如果不是整数
if type(page) != int:
# 强制让页码为1
page = 1
self.page = page
self.start = (page - 1) * page_size
self.end = page * page_size
# 每页展示的数据行数
self.page_queryset = queryset[self.start:self.end]
total_data_count = queryset.count() # 数据行数
total_page_count, div = divmod(total_data_count, page_size)
if div:
total_page_count += 1
self.total_page_count = total_page_count # 总页码数量
self.page_show = page_show # 当前页前后展示的页码数量
self.request = request
def html(self):
# 如果总页码数量大于 11
if self.total_page_count > self.page_show * 2 + 1:
# 如果当前页面页码位置小于等于5
if self.page <= 5:
start_page = 1
end_page = self.page_show * 2 + 2
# 否则,当前页面页码位置大于5时
else:
# 防止页码超出范围
if self.page >= self.total_page_count - self.page_show:
start_page = self.total_page_count - self.page_show * 2
end_page = self.total_page_count + 1
else:
# 计算出当前页的前5页和后5页
start_page = self.page - self.page_show
end_page = self.page + self.page_show + 1
else:
start_page = 1
end_page = self.total_page_count + 1
######## 创建页码 ########
# 页码
page_str_list = []
# self.query_dict.setlist(self.page_param, [1])
# page_str_list.append('<li><a href="?page={}">{}</a></li>'.format(self.query_dict.urlencode()))
# 跳到首页
self.query_dict.setlist(self.page_param, [1])
self.head_page = '<li><a href="?{}" aria-label="Previous"><span aria-hidden="true">首页</span></a></li>'.format(self.query_dict.urlencode())
page_str_list.append(self.head_page)
# 跳到上10页
# 如果当前页面小于 11, 防止超过最小页数
if self.page < self.page_show * 2 + 1:
self.query_dict.setlist(self.page_param, [1])
prev = '<li><a href="?{}">{}</a></li>'.format(
self.query_dict.urlencode(), "<<")
page_str_list.append(prev)
else:
self.query_dict.setlist(self.page_param, [self.page - 10])
prev = '<li><a href="?{}">{}</a></li>'.format(
self.query_dict.urlencode(), "<<")
page_str_list.append(prev)
for i in range(start_page, end_page):
# 如果是当前页,高亮显示页码颜色
if self.page == i:
self.query_dict.setlist(self.page_param, [i])
ele = '<li class="active"><a href="?{}">{}</a></li>'.format(
self.query_dict.urlencode(), i)
else:
self.query_dict.setlist(self.page_param, [i])
ele = '<li><a href="?{}">{}</a></li>'.format(
self.query_dict.urlencode(), i)
page_str_list.append(ele)
# 跳到下10页
# 如果当前页面页数 大于 最大页面数量减去(page_show*2+1),则直接跳到最后一页,防止超过最大页数
if self.page >= self.total_page_count - self.page_show * 2 + 1:
self.query_dict.setlist(self.page_param, [self.total_page_count])
next = '<li><a href="?{}">{}</a></li>'.format(
self.query_dict.urlencode(), ">>")
page_str_list.append(next)
else:
self.query_dict.setlist(self.page_param, [self.page + 10])
next = '<li><a href="?page={}">{}</a></li>'.format(
self.query_dict.urlencode(), ">>")
page_str_list.append(next)
# 跳到尾页
self.query_dict.setlist(self.page_param, [self.total_page_count])
self.end_page = '<li><a href="?{}" aria-label="Next"><span aria-hidden="true">尾页</span></a></li>'.format(self.query_dict.urlencode())
page_str_list.append(self.end_page)
self.page_string = mark_safe("".join(page_str_list))
对上面一段代码的解析:
query_dict = copy.deepcopy(request.GET)
query_dict._mutable = True
self.query_dict = query_dict
上面这一段代码是获取保留目前已有的URL参数
query_dict._mutable = True
表示将URL改为参数可拼接
self.query_dict.setlist(self.page_param, [self.page + 10])
next = '<li><a href="?page={}">{}</a></li>'.format(self.query_dict.urlencode(), ">>")
上面这一段代码表示在原来URL参数的基础上进行拼接,不是像原来一样直接覆盖URL参数
setlist
表示增加URL参数
self.query_dict.urlencode()
表示将self.page_param
与数值self.page + 10
拼接起来,不会讲原来已有的URL参数覆盖
例如setlist(page, [10])
表示page=10
修改myproject/employee_management/templates/pretty_list.html
<ul class="pagination">
{{ page_string }}
</ul>
浏览器访问测试
但是目前输入页码跳转到指定页
的功能还是有这个问题,现在还无法解决,需要使用到ajax
用户列表增加分页
修改myproject/employee_management/views.py
def user_list(request):
"""用户列表"""
# 获取所有用户列表
queryset = UserInfo.objects.all()
page_object = Pagination(request, queryset, page_size=2)
# 用 python 的语法获取数据
"""
for obj in user_data:
# obj.get_gender_display() 表示匹配 男/女,原始字段名为gender,obj.get_字段名称_display()
# obj.create_time.strftime("%Y-%m-%d") 表示将时间格式转换成固定格式的字符串
# obj.depart.title 表示获取depart_id对应的部门名称,因为我们在models中定义表时与另外一张表设置了级联关系,有外键
print(obj.id, obj.name, obj.password, obj.age, obj.account, obj.get_gender_display(), obj.depart.title, obj.create_time.strftime("%Y-%m-%d"))
"""
page_object.html()
context = {
"queryset": page_object.page_queryset,
"page_string": page_object.page_string,
}
return render(request, "user_list.html", context)
修改myproject/employee_management/templates/user_list.html
{% for obj in queryset %}
...
<ul class="pagination">
{{ page_string }}
</ul>
浏览器访问测试
部门列表增加分页
修改myproject/employee_management/views.py
def depart_list(request):
"""部门列表"""
queryset = Department.objects.all()
page_object = Pagination(request, queryset, page_size=2)
page_object.html()
context = {
"queryset": page_object.page_queryset,
"page_string": page_object.page_string,
}
return render(request, "depart_list.html", context)
修改myproject/employee_management/templates/depart_list.html
{% for obj in queryset %}
...
<ul class="pagination">
{{ page_string }}
</ul>
浏览器访问
项目代码优化
ModelForm优化
新建myproject/employee_management/utils/modelform.py
from django import forms
class BootStrapModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环ModelForm中的所有字段,给每个字段的插件设置
for _, field in self.fields.items():
# 字段中有属性,保留原来的属性,没有属性,才增加
if field.widget.attrs:
field.widget.attrs["class"] = "form-control"
else:
field.widget.attrs = {
"class": "form-control",
}
修改myproject/employee_management/views.py
将目前的三个class类改为继承
BootStrapModelForm
自定义类
class UserModelForm(BootStrapModelForm):
class PrettyModelForm(BootStrapModelForm):
class PrettyEditModelForm(BootStrapModelForm):
删除三个class的
init函数
刷新浏览器查看效果,你会发现和以前一样,没有变化
整合form
新建myproject/employee_management/form
目录
新建myproject/employee_management/form/form.py
文件,将/root/python/myproject/employee_management/views.py
文件中的相关class移动到此文件中
from employee_management.utils.modelform import BootStrapModelForm
from employee_management.models import UserInfo, PrettyNum
from django.core.exceptions import ValidationError
from django import forms
class UserModelForm(BootStrapModelForm):
### 自定义数据校验
# 例如: 用户名最小三个字符
#name = forms.CharField(min_length=3, label="用户名")
class Meta:
model = UserInfo
fields = ["name", "password", "age", "account", "create_time", "gender", "depart"]
# 逐一控制标签的样式
# widgets = {
# "name": forms.TextInput(attrs={"class": "form-control"}),
# "password": forms.PasswordInput(attrs={"class": "form-control"}),
# }
# 这里让日期可以手动点击鼠标选择,所以单独拎出来,加上日期插件
widgets = {
# "create_time": forms.DateInput(attrs={'class': 'form-control', 'id': 'myDate'}),
"create_time": forms.DateInput(attrs={'id': 'myDate'}),
}
class PrettyModelForm(BootStrapModelForm):
# 数据校验: 验证方式1
# mobile = forms.CharField(
# label="手机号",
# validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'),],
# )
class Meta:
model = PrettyNum
# fields = "__all__" 表示取表中所有的字段
fields = ['mobile', 'price', 'level', 'status']
# exclude = ['level'] 表示取除了表中的某个字段的所有字段
# 数据校验: 验证方式2
def clean_mobile(self):
txt_mobile = self.cleaned_data['mobile']
if len(txt_mobile) != 11:
# 验证不通过
raise ValidationError('格式错误')
exists_data = PrettyNum.objects.filter(mobile=txt_mobile).exists()
if exists_data:
raise ValidationError("手机号已存在")
# 验证通过
return txt_mobile
class PrettyEditModelForm(BootStrapModelForm):
# mobile = forms.CharField(disabled=True, label="手机号")
# 数据校验: 验证方式1
# mobile = forms.CharField(
# label="手机号",
# validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'),],
# )
class Meta:
model = PrettyNum
# fields = "__all__" 表示取表中所有的字段
fields = ['mobile', 'price', 'level', 'status']
# exclude = ['level'] 表示取除了表中的某个字段的所有字段
# 数据校验: 验证方式2
def clean_mobile(self):
txt_mobile = self.cleaned_data['mobile']
if len(txt_mobile) != 11:
# 验证不通过
raise ValidationError('格式错误')
# exclude 表示排除哪一个数据
# self.instance.pk 表示当前编辑的哪一行 id
exists_data = PrettyNum.objects.exclude(id=self.instance.pk).filter(mobile=txt_mobile).exists()
if exists_data:
raise ValidationError("手机号已存在")
# 验证通过
return txt_mobile
整理之后的views.py
文件是这样的
优化views.py
我们也可以将
/root/python/myproject/employee_management/views.py
进行拆分
按照部门进行拆分
新建/root/python/myproject/employee_management/views
目录
然后在其下依次新建user.py
depart.py
pretty.py
depart.py
from django.shortcuts import render, redirect
from employee_management.models import Department
from employee_management.utils.pagination import Pagination
def depart_list(request):
"""部门列表"""
queryset = Department.objects.all()
page_object = Pagination(request, queryset, page_size=2)
page_object.html()
context = {
"queryset": page_object.page_queryset,
"page_string": page_object.page_string,
}
return render(request, "depart_list.html", context)
def depart_add(request):
"""部门添加"""
if request.method == "GET":
return render(request, "depart_add.html")
# 获取用户提交的部门数据
depart_title = request.POST.get("depart_title")
# 保存到数据库
Department.objects.create(title=depart_title)
# 重定向回部门列表
return redirect("/depart/list/")
def depart_delete(request):
"""部门删除"""
nid = request.GET.get('nid')
Department.objects.filter(id=nid).delete()
# 重定向回部门列表
return redirect("/depart/list/")
def depart_edit(request, nid):
"""部门编辑"""
if request.method == "GET":
# 根据nid,获取数据
row_object = Department.objects.filter(id=nid).first()
return render(request, 'depart_edit.html', {"row_object": row_object})
# 如果是POST请求,保存修改
depart_title = request.POST.get('depart_title')
Department.objects.filter(id=nid).update(title=depart_title)
# 重定向回部门列表
return redirect('/depart/list/')
user.py
from django.shortcuts import render, redirect
from employee_management.models import UserInfo
from employee_management.utils.pagination import Pagination
from employee_management.form.form import UserModelForm
def user_list(request):
"""用户列表"""
# 获取所有用户列表
queryset = UserInfo.objects.all()
page_object = Pagination(request, queryset, page_size=2)
# 用 python 的语法获取数据
"""
for obj in user_data:
# obj.get_gender_display() 表示匹配 男/女,原始字段名为gender,obj.get_字段名称_display()
# obj.create_time.strftime("%Y-%m-%d") 表示将时间格式转换成固定格式的字符串
# obj.depart.title 表示获取depart_id对应的部门名称,因为我们在models中定义表时与另外一张表设置了级联关系,有外键
print(obj.id, obj.name, obj.password, obj.age, obj.account, obj.get_gender_display(), obj.depart.title, obj.create_time.strftime("%Y-%m-%d"))
"""
page_object.html()
context = {
"queryset": page_object.page_queryset,
"page_string": page_object.page_string,
}
return render(request, "user_list.html", context)
def user_model_form_add(request):
"""添加用户(ModelForm版本)"""
if request.method == "GET":
form = UserModelForm()
return render(request, "user_model_form_add.html", {"form": form})
# 用户POST请求提交数据,需要进行数据校验
form = UserModelForm(data=request.POST)
if form.is_valid():
print(form.cleaned_data)
# 直接保存至数据库
form.save()
return redirect("/user/list/")
# 校验失败(在页面上显示错误信息)
return render(request, "user_model_form_add.html", {"form": form})
def user_edit(request, nid):
"""编辑用户"""
row_obj = UserInfo.objects.filter(id=nid).first()
# GET请求
if request.method == "GET":
form = UserModelForm(instance=row_obj)
return render(request, "user_edit.html", {"form": form})
# POST请求
form = UserModelForm(data=request.POST, instance=row_obj)
if form.is_valid():
form.save()
return redirect("/user/list/")
return render(request, "user_edit.html", {"form": form})
def user_delete(request, nid):
"""用户删除"""
UserInfo.objects.filter(id=nid).delete()
return redirect("/user/list/")
pretty.py
from django.shortcuts import render, redirect
from employee_management.models import PrettyNum
from employee_management.utils.pagination import Pagination
from employee_management.form.form import PrettyModelForm, PrettyEditModelForm
def pretty_list(request):
"""靓号列表"""
print(request.GET)
print(request.GET.urlencode())
data_dict = {}
# 如果是空字典,表示获取所有
# 不加后面的 "", 首次访问浏览器,搜索框中不会显示前端页面中的 placeholder="Search for..." 属性
search_data = request.GET.get('query', "")
if search_data:
data_dict["mobile__contains"] = search_data
queryset = PrettyNum.objects.filter(**data_dict).order_by("-level")
### 引入封装的 Pagination 类并初始化
# 初始化
page_object = Pagination(request, queryset, page_size=10, page_param="page")
page_queryset = page_object.page_queryset
# 调用对象的html方法,生成页码
page_object.html()
page_string = page_object.page_string
context = {
"pretty_data": page_queryset, # 分页的数据
"search_data": search_data, # 搜索的内容
"page_string": page_string, # 页码
}
return render(request, "pretty_list.html", context)
def pretty_add(request):
"""添加靓号"""
if request.method == "GET":
form = PrettyModelForm()
return render(request, "pretty_add.html", {"form": form})
# 用户POST请求提交数据,需要进行数据校验
form = PrettyModelForm(data=request.POST)
if form.is_valid():
print(form.cleaned_data)
# 直接保存至数据库
form.save()
return redirect("/pretty/list/")
# 校验失败(在页面上显示错误信息)
return render(request, "pretty_add.html", {"form": form})
def pretty_edit(request, nid):
"""编辑靓号"""
row_obj = PrettyNum.objects.filter(id=nid).first()
# GET请求
if request.method == "GET":
form = PrettyEditModelForm(instance=row_obj)
return render(request, "pretty_edit.html", {"form": form})
# POST请求
form = PrettyEditModelForm(data=request.POST, instance=row_obj)
if form.is_valid():
form.save()
return redirect("/pretty/list/")
return render(request, "pretty_edit.html", {"form": form})
def pretty_delete(request, nid):
"""删除靓号"""
PrettyNum.objects.filter(id=nid).delete()
return redirect('/pretty/list/')
重命名原来的views.py
文件为views_old.py
,不然会跟目前的views目录冲突
修改myproject/myproject/urls.py
from django.contrib import admin
from django.urls import path
from employee_management.views import depart,user,pretty
urlpatterns = [
path('admin/', admin.site.urls),
path('depart/list/', depart.depart_list),
path('depart/add/', depart.depart_add),
path('depart/delete/', depart.depart_delete),
path('depart/<int:nid>/edit/', depart.depart_edit),
path('user/list/', user.user_list),
path('user/model/form/add/', user.user_model_form_add),
path('user/<int:nid>/edit/', user.user_edit),
path('user/<int:nid>/delete/', user.user_delete),
path('pretty/list/', pretty.pretty_list),
path('pretty/add/', pretty.pretty_add),
path('pretty/<int:nid>/edit/', pretty.pretty_edit),
path('pretty/<int:nid>/delete/', pretty.pretty_delete),
]
刷新浏览器,效果还是一样,不同的是我们的代码更加规整
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/100699.html