使用的项目名称:PyCharmWork\WorkforceManager
1.创建新项目
步骤:Django web开发(三)Django_django 个人网站开发-优快云博客
数据库建设:然后终端生成
class PrettyNum(models.Model):
"""靓号管理"""
# 定义字段及其属性
mobile = models.CharField(max_length=11, verbose_name="手机号")
price = models.DecimalField(max_digits=10, decimal_places=2,verbose_name="价格")
level = models.IntegerField(
choices=[
(1, '1级'),
(2, '2级'),
(3, '3级'),
(4, '4级')
],
verbose_name="级别"
)
status = models.IntegerField(
choices=[
(1, '未占用'),
(2, '已占用')
],
verbose_name="状态"
)
def __str__(self):
# 定义模型的字符串表示形式
return f"{self.mobile} - {self.get_level_display()} - {self.get_status_display()}"
靓号列表
path('pretty/list/', views.pretty_list),
由于已经弄了from app01 import models,所以后面调用都是models.xxx,ai的总不写models
order_by("-level")# order_by排序, 这里指以level倒序从高到低排
def pretty_list(request):
# order_by排序, 这里指以level倒序从高到低排
queryset = models.PrettyNum.objects.all().order_by("-level") # 获取所有的靓号
return render(request, 'pretty_list.html', {'queryset': queryset})
html参考之前的列表代码
添加:modelform、数据校验
modelform
利用modelform时,fields可以自定义某些字段、选取所有、排除部分字段
利用def __init__循环找到所有的插件,添加 "class": "form-control",使输入框变统一样式
注意def和Meta是同一级的
from django import forms
class PrettyModelForm(forms.ModelForm):
class Meta:
model = models.PrettyNum
# fields = ['mobile', 'price', 'level', 'status']
# exclude = ('level',)
fields = "__all__"
# 循环找到所有的插件,添加 "class": "form-control"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
# 可以排除指定的字段
# if name == "password":
# continue
# print(name, field)
# form - control是样式,placeholder是输入框内的文字
field.widget.attrs = {"class": "form-control","placeholder": field.label}
view:
def pretty_add(request):
"""靓号添加"""
if request.method == 'GET':
form = PrettyModelForm()
return render(request, 'pretty_add.html', {'form': form})
else:
# 用户POST请求提交数据,需要进行数据校验
form = PrettyModelForm(data=request.POST)
if form.is_valid():
# 直接保存至数据库
form.save()
return redirect('/pretty/list/')
# 校验失败(在页面上显示错误信息)
return render(request, 'pretty_add.html', {'form': form})
数据校验
在views.py里的class里写
方法一:字段+正则(较简单)
在class Meta:前写
mobile = forms.CharField(
label="手机号",
validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'), ],
)
方法二:钩子方法
在def __init__(self, *args, **kwargs):后面写
# 数据校验方法2
def clean_mobile(self):
txt_mobile = self.cleaned_data["mobile"]
if len(txt_mobile) != 11:
# 验证不通过
raise ValidationError("格式错误")
# 验证通过 用户输入的值返回
return txt_mobile
两种方式位置如下:
class PrettyModelForm(forms.ModelForm):
# 数据校验 方法1
mobile = forms.CharField(
label="手机号",
validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'), ],
)
class Meta:
model = models.PrettyNum
# fields = ['mobile', 'price', 'level', 'status']
# exclude = ('level',)
fields = "__all__"
# 循环找到所有的插件,添加 "class": "form-control"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
# 可以排除指定的字段
# if name == "password":
# continue
# print(name, field)
# form - control是样式,placeholder是输入框内的文字
field.widget.attrs = {"class": "form-control", "placeholder": field.label}
# # 数据校验方法2
# def clean_mobile(self):
# txt_mobile = self.cleaned_data["mobile"]
# if len(txt_mobile) != 11:
# # 验证不通过
# raise ValidationError("格式错误")
# # 验证通过 用户输入的值返回
# return txt_mobile
编辑靓号
也要数据校验,调用之前的modelform就可以,也可以重新写限定只能修改哪几个input框,也可以修改modelform让某些字段出现input框但不可更改
代码就跟之前的编辑部分一样,省略了:Django web 开发(四) - 员工管理系统(一)-优快云博客
不允许数据重复
不允许手机号重复
-添加: 如果手机号已存在,提示"手机号已存在"
-编辑: 如果手机号除了当前手机号以外已存在,提示"手机号已存在"
添加和编辑的逻辑不太一样,编辑需要将它自己先排除然后再做判断
"添加"功能的手机号重复验证
修改modelform或者在数据库里给号码加上唯一性约束(没试)
只能用数据校验的方法2钩子方法 写里面
# 验证是否存在 exists_data = models.PrettyNum.objects.filter(mobile=txt_mobile).exists() if exists_data: raise ValidationError("手机号已存在")
class PrettyModelForm(forms.ModelForm):
# # 数据校验 方法1
# mobile = forms.CharField(
# label="手机号",
# validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'), ],
# )
class Meta:
model = models.PrettyNum
# fields = ['mobile', 'price', 'level', 'status']
# exclude = ('level',)
fields = "__all__"
# 循环找到所有的插件,添加 "class": "form-control"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
# 可以排除指定的字段
# if name == "password":
# continue
# print(name, field)
# form - control是样式,placeholder是输入框内的文字
field.widget.attrs = {"class": "form-control", "placeholder": field.label}
# 数据校验方法2
def clean_mobile(self):
txt_mobile = self.cleaned_data["mobile"]
if len(txt_mobile) != 11:
# 验证不通过
raise ValidationError("格式错误")
# 验证是否存在
exists_data = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()
if exists_data:
raise ValidationError("手机号已存在")
# 验证通过 用户输入的值返回
return txt_mobile
"编辑"功能的手机号重复验证
懒得写了,感觉用不到,要不就干脆禁止编辑手机号,或者参考人家这篇Django web 开发(四) - Django项目实践(五)-靓号管理_django靓号-优快云博客
删除(略)
查/模糊查询
修改pretty_list,这是列表展示的功能
gt:gather? than大于
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"开头的
首先设置data_dict为空字典,当不传搜索参数时展示所有数据,传参后展示目的数据
filter(**data_dict)是条件筛选,没有条件就等于all
传入搜索参数后,搜索后并把这个值体现在前端的框框里
(红框为新增的)
def pretty_list(request):
"""靓号列表"""
"""实现搜索功能"""
data_dict = {}
# 不加后面的 "", 首次访问浏览器,搜索框中不会显示前端页面中的 placeholder="Search for..." 属性
search_data = request.GET.get('q', "")
if search_data: #value为真,即传入了搜索参数
# mobile_contains 表示筛选出字段mobile 包含 value数据的行
data_dict["mobile__contains"] = search_data
# 没传参就正常显示所有的
"""排序"""
# order_by排序, 这里指以level倒序从高到低排
# 获取经过上述搜索的目的靓号,filter(**data_dict)是条件筛选,没有条件就等于all
queryset = models.PrettyNum.objects.filter(**data_dict).order_by("-level")
return render(request, 'pretty_list.html', {'queryset': queryset,"search_data": search_data})
前端:
注意,input框要命名为q,接受传入的q,以及value="{{ search_data }}"加上后是使搜索后输入值不会清零
{# 新建/搜索按钮#}
<nav class="navbar">
<div style="margin-bottom: 20px;" class="container-fluid">
<a class="btn btn-success" href="/pretty/add/" target="_blank">
新建靓号modelform
</a>
<form class="d-flex" role="search" method="get">
{#value="{{ search_data }}"加上后是使搜索后输入值不会清零#}
<input name="q" class="form-control me-2" type="search" placeholder="搜索靓号" value="{{ search_data }}" aria-label="Search">
<button class="btn btn-outline-success" type="submit">go</button>
</form>
</div>
</nav>
分页
这里使用Django的paginator(分页)功能较为方便
但也可以自定义pagination使之更加方便
Django的paginator整体思路
- 获取数据:从数据库查询需要分页的数据。
- 创建分页器:使用
Paginator
类创建分页器实例。 - 获取当前页:根据请求中的页码参数获取当前页的对象列表。
- 渲染分页:在模板中使用分页器对象渲染分页链接。
1. 在视图中使用分页
from django.core.paginator import Paginator
from django.shortcuts import render
def my_view(request):
object_list = MyModel.objects.all() # 获取所有对象
paginator = Paginator(object_list, 10) # 每页显示10个对象
# 获取当前页
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'my_template.html', {'page_obj': page_obj})
request.GET.get('page')
:从GET请求中获取名为page
的查询参数,默认为None
。page_obj
:当前页的对象列表,是一个Page
对象。get_page()
:Paginator
实例的方法,根据页码获取对应的页。get_page
方法接受一个页码,并返回一个包含该页对象的Page
对象。
和之前的排序搜索放一起
def pretty_list(request):
"""靓号列表"""
"""实现搜索功能"""
data_dict = {}
# 不加后面的 "", 首次访问浏览器,搜索框中不会显示前端页面中的 placeholder="Search for..." 属性
search_data = request.GET.get('q', "")
if search_data: # value为真,即传入了搜索参数
# mobile_contains 表示筛选出字段mobile 包含 value数据的行
data_dict["mobile__contains"] = search_data
# 没传参就正常显示所有的
"""排序"""
# order_by排序, 这里指以level倒序从高到低排
# 获取经过上述搜索的目的靓号,filter(**data_dict)是条件筛选,没有条件就等于all
queryset = models.PrettyNum.objects.filter(**data_dict).order_by("-level")
"""分页"""
paginator = Paginator(queryset, 7) # 每页显示7个靓号
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'pretty_list.html', {"search_data": search_data, 'page_obj': page_obj})
2. 在模板中显示分页
原先的列表显示还是那样(注意变量名有没有变)
后面加一个{#分页导航#}
<div class="pagination">
<span class="step-links">
第一页/上一页
<a href="?page=1">第一页</a>
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">上一页</a>
{% endif %}
中间页码区
<span class="current">
页码 {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
下一页/最后一页
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">下一页</a>
{% endif %}
<a href="?page={{ page_obj.paginator.num_pages }}">最后一页</a>
</span>
</div>
传入的page_obj
:当前页的对象列表
{% if page_obj.has_previous %}
:检查是否有前一页。{% if page_obj.has_next %}
:检查是否有后一页。page_obj.previous_page_number
:前一页的页码。page_obj.next_page_number
:后一页的页码。page_obj.number
:当前页码。page_obj.paginator
:当前页的分页器对象,包含了分页的相关信息。page_obj.paginator.num_pages
:总页数。
?page={{}}
是一个用于构建URL查询字符串的模板标签,其中{{}}
是一个占位符,用于动态插入变量的值。page_obj.paginator.page_range
返回一个包含所有页码的列表。这个列表代表了分页器中所有可能的页码,可以用于在模板中生成分页链接。
下面是一个用了样式的分页,让只显示前后三页好像
{#分页导航#}
<nav aria-label="Page navigation example">
<ul class="pagination justify-content-center">
<li class="page-item">
<a class="page-link" href="?page=1" aria-label="First">第一页</a>
</li>
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}"
aria-label="Previous">上一页</a>
</li>
{% endif %}
{#循环所有页码 page...range 是一个包含所有页码的列表 #}
{% for num in page_obj.paginator.page_range %}
{# 检查当前页:检查当前遍历到的页码 num 是否等于当前页的页码 page_obj.number #}
{% if page_obj.number == num %}
{# {#如果当前页码与遍历到的页码相同,生成一个带有 active 类的列表项,表示当前页。#}
{# {#这里使用 <span> 而不是 <a>,因为当前页不需要链接#}
<li class="page-item active" aria-current="page">
<span class="page-link">{{ num }}</span>
</li>
{#检查页码是否在当前页码前后3页的范围内。|add:'-3' 和 |add:'3' 是Django模板过滤器,用于进行简单的算术运算。#}
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
{#生成非当前页的HTML:如果页码在当前页前后3页的范围内,生成一个包含链接的列表项#}
<li class="page-item">
<a class="page-link" href="?page={{ num }}">{{ num }}</a>
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next">下一页</a>
</li>
{% endif %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}" aria-label="Last">最后一页</a>
</li>
</ul>
</nav>
自定义paginyion
后面要用ajax
在app01-utils文件夹(自建)下新建paginyion.py
bootsrap样式看它写的啥,li、a标签里有样式的就在标签里面加
分页组件
"""
自定义的分页组件
"""
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):
"""
request: 请求的对象
queryset: 符合条件的数据(根据此数据进行分页处理)
page_size: 每页显示多少条数据
page_param: 获取在URL中传递的分页参数, 例如: /pretty/list/?page=21
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 class="page-item">'
'<a class="page-link" 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 class="page-item">'
'<a class="page-link" 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 class="page-item">'
'<a class="page-link" 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 page-item">'
'<a class="page-link" href="?{}">{}</a>'
'</li>').format(
self.query_dict.urlencode(), i)
else:
self.query_dict.setlist(self.page_param, [i])
ele = ('<li class="page-item">'
'<a class="page-link" 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 class="page-item">'
'<a class="page-link" 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 class="page-item">'
'<a class="page-link" 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 class="page-item">'
'<a class="page-link" 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))
"""
视图文件:
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)
"""
在视图中:
def manager_list(request):
queryset = models.Admin.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, "manager_list.html", context)
html
{% for obj in queryset %}
...
<ul class="pagination">
{{ page_string }}
</ul>
老师的分页
修改了样式
"""
自定义分页组件
"""
"""
使用方法
视图函数:
def Task_list(request)
# 1.根据自己情况筛选数据(其他功能已经获取数据的话就不用多此一举了
queryset = models.Task.objects.all()
# 2.实例化分页对象
page_object = Pagination(request,queryset)
# 3.在原context里替换/添加这俩
context = {
"queryset": page_object.page_queryset, # 分完页的数据
"page_string": page_object.html() # 生成页码
}
return render(request,"task_list.html",context)
在html页面中:
注意for循环那一部分一般显示列表时就有了,就不用重复添加了,ur部分放表格下面
{% for obj in queryset %}
{{ obj.xx }}
{% endfor %}
<ul class="pagination">
{{ page_string }}
</ul>
"""
from django.utils.safestring import mark_safe
from django import forms
class Pagination(object):
def __init__(self, request, queryset, page_size=2, page_param="page", plus=5):
"""
:param request: 请求的对象
:param queryset:查询的数据,符合条件的数据对这个进行分页处理
:param page_size:每页显示多条数据
:param page_param:在URL中传递获取分页的参数,列如:/etty/list/?page=12
:param plus:显示当前页的,前、后几页(页码)
"""
import copy
query_dict = copy.deepcopy(request.GET)
query_dict._mutable = True
self.query_dict = query_dict
self.page_param = page_param
page = request.GET.get(page_param, "1") # 把request获取前端get请求的方法,封装到page中,页码
if page.isdecimal(): # 处理页码,判断页码是否是正常传入数字,而不是字符串
page = int(page)
else:
page = 1 # 前端传入页码不规范,则默认为1
self.page = page
self.page_size = page_size
# 计算分页页码,sql值
self.start = (page - 1) * page_size
self.end = page * page_size
self.page_queryset = queryset[self.start: self.end] # 分完页的数据
# total_count = models.PrettyNum.objects.filter(**data_dict).order_by("-price").count()
total_count = queryset.count() # 数据总条数
total_page_count, div = divmod(total_count, page_size) # 总页码 = 数据总条数/每页显示数据条数
if div:
total_page_count += 1
self.total_page_count = total_page_count
self.plus = plus # 显示前后页码条数
def html(self):
"""
页码、页码搜索
"""
# 计算出,显示当前页的前5页、后5页
if self.total_page_count <= 2 * self.plus + 1:
# 数据库中的数据比较少,都没有达到11页。
start_page = 1
end_page = self.total_page_count
else:
# 数据库中的数据比较多 > 11页。
# 当前页<5时(小极值)
if self.page <= self.plus:
start_page = 1
end_page = 2 * self.plus + 1
else:
# 当前页 > 5
# 当前页+5 > 总页面
if (self.page + self.plus) > self.total_page_count:
start_page = self.total_page_count - 2 * self.plus
end_page = self.total_page_count
else:
start_page = self.page - self.plus
end_page = self.page + self.plus
# 页码
page_str_list = []
self.query_dict.setlist(self.page_param, [1])
page_str_list.append('<li class="page-item">'
'<a class="page-link" href="?{}" aria-label="Previous">'
'<span aria-hidden="true">首页</span></a></li>'.format(self.query_dict.urlencode()))
# 上一页
if self.page > 1:
self.query_dict.setlist(self.page_param, [self.page - 1])
prev = ('<li class="page-item">'
'<a class="page-link" href="?{}">{}</a>'
'</li>'
).format(
self.query_dict.urlencode(), "<<")
else:
self.query_dict.setlist(self.page_param, [1])
prev = ('<li class="page-item">'
'<a class="page-link" href="?{}">{}</a>'
'</li>'
).format(
self.query_dict.urlencode(), "<<")
page_str_list.append(prev)
# 页面
for i in range(start_page, end_page + 1):
self.query_dict.setlist(self.page_param, [i])
if i == self.page:
ele = ('<li class="active page-item">'
'<a class="page-link" href="?{}">{}</a>'
'</li>').format(self.query_dict.urlencode(), i)
else:
ele = ('<li class="page-item">'
'<a class="page-link" href="?{}">{}</a>'
'</li>').format(self.query_dict.urlencode(), i)
page_str_list.append(ele)
# 下一页
if self.page < self.total_page_count:
self.query_dict.setlist(self.page_param, [self.page + 1])
prev = ('<li class="page-item">'
'<a class="page-link" href="?{}">{}</a>'
'</li>').format(
self.query_dict.urlencode(), ">>")
else:
self.query_dict.setlist(self.page_param, [self.total_page_count])
prev = ('<li class="page-item">'
'<a class="page-link" href="?page={}">{}</a>'
'</li>').format(
self.query_dict.urlencode(), ">>")
page_str_list.append(prev)
# 尾页
self.query_dict.setlist(self.page_param, [self.total_page_count])
page_str_list.append(('<li class="page-item">'
'<a class="page-link" href="?{}" aria-label="Next">'
'<span aria-hidden="true">尾页</span></a></li>'
).format(self.query_dict.urlencode()))
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_str_list.append(search_string)
page_string = mark_safe("".join(page_str_list))
return page_string
未修改版(老师)
"""
自定义分页组件
"""
from django.utils.safestring import mark_safe
from django import forms
class Pagination(object):
def __init__(self, request, queryset, page_size=10, page_param="page", plus=5):
"""
:param request: 请求的对象
:param queryset:查询的数据,符合条件的数据对这个进行分页处理
:param page_size:每页显示多条数据
:param page_param:在URL中传递获取分页的参数,列如:/etty/list/?page=12
:param plus:显示当前页的,前、后几页(页码)
"""
import copy
query_dict = copy.deepcopy(request.GET)
query_dict._mutable = True
self.query_dict = query_dict
self.page_param = page_param
page = request.GET.get(page_param, "1") # 把request获取前端get请求的方法,封装到page中,页码
if page.isdecimal(): # 处理页码,判断页码是否是正常传入数字,而不是字符串
page = int(page)
else:
page = 1 # 前端传入页码不规范,则默认为1
self.page = page
self.page_size = page_size
# 计算分页页码,sql值
self.start = (page - 1) * page_size
self.end = page * page_size
self.page_queryset = queryset[self.start: self.end] # 分完页的数据
# total_count = models.PrettyNum.objects.filter(**data_dict).order_by("-price").count()
total_count = queryset.count() # 数据总条数
total_page_count, div = divmod(total_count, page_size) # 总页码 = 数据总条数/每页显示数据条数
if div:
total_page_count += 1
self.total_page_count = total_page_count
self.plus = plus # 显示前后页码条数
def html(self):
"""
页码、页码搜索
"""
# 计算出,显示当前页的前5页、后5页
if self.total_page_count <= 2 * self.plus + 1:
# 数据库中的数据比较少,都没有达到11页。
start_page = 1
end_page = self.total_page_count
else:
# 数据库中的数据比较多 > 11页。
# 当前页<5时(小极值)
if self.page <= self.plus:
start_page = 1
end_page = 2 * self.plus + 1
else:
# 当前页 > 5
# 当前页+5 > 总页面
if (self.page + self.plus) > self.total_page_count:
start_page = self.total_page_count - 2 * self.plus
end_page = self.total_page_count
else:
start_page = self.page - self.plus
end_page = self.page + self.plus
# 页码
page_str_list = []
self.query_dict.setlist(self.page_param, [1])
page_str_list.append('<li><a href="?{}">首页</a></li>'.format(self.query_dict.urlencode()))
# 上一页
if self.page > 1:
self.query_dict.setlist(self.page_param, [self.page - 1])
prev = '<li><a href="?{}">上一页</a></li>'.format(self.query_dict.urlencode())
else:
self.query_dict.setlist(self.page_param, [1])
prev = '<li><a href="?{}">上一页</a></li>'.format(self.query_dict.urlencode())
page_str_list.append(prev)
# 页面
for i in range(start_page, end_page + 1):
self.query_dict.setlist(self.page_param, [i])
if i == self.page:
ele = '<li class="active"><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
else:
ele = '<li><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
page_str_list.append(ele)
# 下一页
if self.page < self.total_page_count:
self.query_dict.setlist(self.page_param, [self.page + 1])
prev = '<li><a href="?{}">下一页</a></li>'.format(self.query_dict.urlencode())
else:
self.query_dict.setlist(self.page_param, [self.total_page_count])
prev = '<li><a href="?{}">下一页</a></li>'.format(self.query_dict.urlencode())
page_str_list.append(prev)
# 尾页
self.query_dict.setlist(self.page_param, [self.total_page_count])
page_str_list.append('<li><a href="?{}">尾页</a></li>'.format(self.query_dict.urlencode()))
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_str_list.append(search_string)
page_string = mark_safe("".join(page_str_list))
return page_string
视图view文件
单分页
def manager_list(request):
### 引入封装的 Pagination 类并初始化
# 初始化
queryset = models.Admin.objects.all()
page_object = Pagination(request, queryset, page_size=2)
# 调用对象的html方法,生成页码
page_object.html()
context = {
"queryset": page_object.page_queryset,# 分页的数据
"page_string": page_object.page_string,# 页码
}
return render(request, "manager_list.html", context)
搜索+分页
def pretty_list(request):
"""实现搜索功能"""
data_dict = {}
# 不加后面的 "", 首次访问浏览器,搜索框中不会显示前端页面中的 placeholder="Search for..." 属性
search_data = request.GET.get('q', "")
if search_data: # value为真,即传入了搜索参数
# mobile_contains 表示筛选出字段mobile 包含 value数据的行
data_dict["mobile__contains"] = search_data
# 没传参就正常显示所有的
"""排序"""
# # order_by排序, 这里指以level倒序从高到低排
# # 获取经过上述搜索的目的靓号,filter(**data_dict)是条件筛选,没有条件就等于all
# queryset = models.PrettyNum.objects.filter(**data_dict).order_by("-level")
# 根据搜索条件去库里获取
queryset = models.PrettyNum.objects.filter(**data_dict)
"""分页"""
### 引入封装的 Pagination 类并初始化
# 初始化
page_object = Pagination(request, queryset, page_size=7)
# 调用对象的html方法,生成页码
page_object.html()
context = {
"queryset": page_object.page_queryset, # 分页的数据
"page_string": page_object.page_string, # 页码
}
return render(request, 'pretty_list.html', context)
HTML
注意这里表单传参写的是对应的不
{#表格区域#}
...
<!-- 分页导航 -->
<ul class="pagination me-3">
{{ page_string }}
</ul>
<!-- 页码输入框 -->
<form class="d-flex" role="search" method="get">
<input class="form-control me-2" type="text" placeholder="请输入页码" aria-label="页码" style="max-width: 300px;">
<button class="btn btn-outline-success" type="submit">跳转</button>
</form>
modelform优化
重新定义的init方法,批量设置
在field.widget.attrs设置样式
class UserModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = '__all__'
# 循环找到所有的插件,添加 "class": "form-control"和placeholder
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
# 可以排除指定的字段
if name == "password":
continue
print(name, field)
field.widget.attrs = {
"class": "form-control",
"placeholder": field.label,
}
将modelform弄成样式,init写模版里面,调用的再写class meta
新建app01-utils文件夹,内建bootstrap.py
bootstrap.py 里的BootStrapModelForm模版
from django import forms
class BootStrapModelForm(forms.ModelForm):
# 循环找到所有的插件,添加 "class": "form-control"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环modelform中所有字段,给每个字段插件设置
for name, field in self.fields.items():
# # 可以排除指定的字段 # if name == "password": continue
# 如果字段中有属性,保留原来的增加新的,没有属性再添加
if field.widget.attrs:
field.widget.attrs['class'] = 'form-control'
field.widget.attrs['placeholder'] = field.label
# 没有的就直接赋个字典
field.widget.attrs = {
"class": "form-control",
"placeholder": field.label,
}
调用:把原先的init删掉,调用BootStrapModelForm,其他照常
from app01.utils.bootstrap import BootStrapModelForm
class PrettyModelForm(BootStrapModelForm):
# # 数据校验 方法1
# mobile = forms.CharField(
# label="手机号",
# validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'), ],
# )
class Meta:
model = models.PrettyNum
# fields = ['mobile', 'price', 'level', 'status']
# exclude = ('level',)
fields = "__all__"
# 数据校验方法2
def clean_mobile(self):
...
文件拆分
导入部分当然是会变的,但是它会自己提醒你改的
注意!!models不能拆(就是数据库表的那个)比较麻烦
form拆分
在app01/utilst目录下新建form.py文件,(也可以直接新建个form目录)
将views.py文件中的相关class移动到此文件中
view拆分
新建/app01/views
目录
然后在其下依次新建user.py
depart.py
pretty.py...
将不同的视图分类放,注意要把原先的views文件删掉
修改urls
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),
]