Python Web开发记录 Day10:Django part4 靓号管理与优化

名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪)
创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)

目录

        • 1、数据库准备
        • 2、靓号列表
        • 3、新建靓号
        • 4、编辑靓号
        • 5、删除靓号
        • 6、靓号搜索
        • 7、分页切换
        • 8、优化(整合分类)

在经过前两篇博客的学习,对Django开发管理模块能明显感到愈发熟练,本篇内容将继续增加管理模块,靓号管理,并在此之后对之前的所实现的模块整体进行一个优化,再往后的博客内容将陆续推展到管理员管理、账户登录、以及Ajax等内容。

1、数据库准备

1.首先在models.py中创建用户表,定义数据表及属性字段。

class PrettyNum(models.Model):"""靓号表"""mobile = models.CharField(verbose_name="手机号", max_length=11)# 想要允许为空 加上null = True,black = Trueprice = models.IntegerField(verbose_name="价格")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)

2.之后在当前页面终端运行以下数据库转移命令

python manage.py migrate
python manage.py makemigrations

之后运行本地服务器,启动Django项目,Django根据models中定义的内容就会帮咱们自动生成对应的数据表

python manage.py runserver 

在这里插入图片描述

在用Django之前实现用户管理功能,我们先在mysql中写入几条数据:

insert into api_prettynum(mobile,price,level,status)values("111111111",19,1,1);insert into api_prettynum(mobile,price,level,status)values("18888888888",20,1,1);insert into api_prettynum(mobile,price,level,status)values("15555555555",22,1,1);

接下来去实现Django靓号管理。

2、靓号列表

同样地,我们采用与部门列表同样的思路来实现用户列表。

1.在urls.py中添加用户列表的路径pretty/list/,并告诉该路径指向的视图view.pretty_list

urls.py

from django.urls import path
from api.views import depart,user,prettyurlpatterns = [# 部门管理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/add/", user.user_add),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),
]

2.在views.py中写出对应的函数,发出请求,并返回响应pretty_list.html

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_dataqueryset = 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_stringhead_page = page_object.head_pageend_page = page_object.end_pagecontext = {"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)

3.创建templates目录下模版html文件pretty_list.html,以此定义部门列表的网页结构和布局。

layout.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><!--Bootstrap框架--><link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.css' %}"><link rel="stylesheet" href="{% static 'plugins/font-awesome-4.7.0/css/font-awesome.css' %}"><!--datetimepicker插件--><link rel="stylesheet" type="text/css"href="{% static 'plugins/bootstrap-datetimepicker/css/bootstrap-datetimepicker.css' %}"><style>.navbar {border-radius: 0;}</style>{% block css %}{% endblock %}
</head>
<body>
<nav class="navbar navbar-default"><div class="container"><div class="navbar-header"><button type="button" class="navbar-toggle collapsed" data-toggle="collapse"data-target="#bs-example-navbar-collapse-1" aria-expanded="false"><span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a class="navbar-brand" href="#">用户管理系统</a></div><div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"><ul class="nav navbar-nav"><li><a href="/depart/list">部门管理</a></li><li><a href="/user/list">用户管理</a></li><li><a href="/pretty/list">靓号管理</a></li><li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li></ul><ul class="nav navbar-nav navbar-right"><li><a href="#">登录</a></li><li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"aria-expanded="false">张三 <span class="caret"></span></a><ul class="dropdown-menu"><li><a href="#">个人资料</a></li><li><a href="#">我的信息</a></li><li><a href="#">Something else here</a></li><li role="separator" class="divider"></li><li><a href="#">注销</a></li></ul></li></ul></div></div>
</nav><div><div class="container">{% block content %}{% endblock %}</div>
</div>{% block js %}<script src="{% static 'js/jquery.min.js' %}"></script><!-- 加载 Bootstrap DateTimePicker JS --><script src="{% static 'plugins/bootstrap-datetimepicker/js/bootstrap-datetimepicker.min.js' %}"></script><script src="{% static 'plugins/bootstrap-datetimepicker/js/locales/bootstrap-datetimepicker.zh-CN.js' %}"></script><script type="text/javascript">$(function () {//当容器加载完成,对容器调用工具函数$("#dt").datetimepicker({language: 'zh-CN', //语言format: 'yyyy-mm-dd',//日期的格式minView: 'month', //可以选择的最小视图initialDate: new Date(),//初始化显示的日期autoclose: true,//设置选择完日期或者时间之后,日否自动关闭日历todayBtn: true,//设置自动显示为今天clearBtn: false//设置是否清空按钮,默认为false});});</script>
{% endblock %}

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><div style="display: flex; align-items: center"><!-- 页面切换 --><div> <!-- 无需再设置float和宽度 --><ul class="pagination">{{ page_string }}</ul></div><!-- 输入页码框 --><div style="width: 200px;margin-bottom: 5px"> <!-- 保持输入框宽度,但不需要float:right --><form method="get"><div class="input-group"><input type="text" name="page" class="form-control" placeholder="页码"><span class="input-group-btn"><button class="btn btn-default" type="submit">跳转</button></span></div></form></div></div>
{% endblock %}

效果:

image-20240314112640113

3、新建靓号

同样地采用ModelForm组件来实现。

1.在urls.py中添加用户列表的路径pretty/add/,并告诉该路径指向的视图view.pretty_add

urls.py

 from django.urls import pathfrom api.views import depart,user,prettyurlpatterns = [# 部门管理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/add/", user.user_add),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),]

2.在views.py中写出对应的函数,发出请求,并返回响应pretty_add.html

views.py

class PrettyModelForm(BootStrapModelForm):# 验证:方式1mobile = forms.CharField(label="手机号",validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'), ],)class Meta:model = models.PrettyNum# fields = "__all__"# exclude = ['level']fields = ["mobile", 'price', 'level', 'status']# 验证:方式2def clean_mobile(self):txt_mobile = self.cleaned_data["mobile"]exists = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()if exists:raise ValidationError("手机号已存在")# 验证通过,用户输入的值返回return txt_mobiledef pretty_add(request):"""添加靓号"""if request.method == "GET":form = PrettyModelForm()return render(request, "pretty_add.html", {"form": form})form = PrettyModelForm(data=request.POST)if form.is_valid():form.save()return redirect('/pretty/list/')return render(request, 'pretty_add.html', {"form": form})

3.创建templates目录下模版html文件pretty_add.html,以此实现用户信息的新增。

pretty_add.html

{% extends 'layout.html' %}{% block content %}<div class="container"><div class="panel panel-default"><div class="panel-heading"><h3 class="panel-title" style="font-weight: bold">新建靓号</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 %}<div class="form-group"><div class="col-sm-offset-2 col-sm-10"><button type="submit" class="btn btn-primary">提 交</button></div></div></form></div></div></div>
{% endblock %}
<form method="post">{% csrf_token %}{% for field in form %}{{ field.label }} : {{ field }}{% endfor %}
</form>

效果:

image-20240314113136689

4、编辑靓号

在完成新建靓号后我们来接着实现编辑靓号。

①编辑靓号

1.在urls.py中添加用户列表的路径pretty/<int:nid>/edit/,并告诉该路径指向的视图view.pretty_edit

urls.py

 from django.urls import pathfrom api.views import depart,user,prettyurlpatterns = [# 部门管理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/add/", user.user_add),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),]

2.在views.py中写出对应的函数,发出请求,并返回响应pretty_edit.html

views.py

def pretty_edit(request, nid):""" 编辑靓号 """row_object = models.PrettyNum.objects.filter(id=nid).first()if request.method == "GET":form = PrettyEditModelForm(instance=row_object)return render(request, 'pretty_edit.html', {"form": form})form = PrettyEditModelForm(data=request.POST, instance=row_object)if form.is_valid():form.save()return redirect('/pretty/list/')return render(request, 'pretty_edit.html', {"form": form})

3.创建templates目录下模版html文件pretty_edit.html,以此实现用户信息的新增。

pretty_edit.html

{% extends 'layout.html' %}{% block content %}<div class="container"><div class="panel panel-default"><div class="panel-heading"><h3 class="panel-title" style="font-weight: bold">编辑靓号</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 %}<div class="form-group"><div class="col-sm-offset-2 col-sm-10"><button type="submit" class="btn btn-primary">提 交</button></div></div></form></div></div></div>
{% endblock %}

效果:

image-20240314120644463

②手机号重复问题

在添加和编辑时,遇到手机号重复的我们应该不能再进行添加或编辑,因此我们可以使用以下方式来解决手机号重复问题,对于:

  • 添加:若手机号已经存在,提示"手机号已存在"。

  • 编辑:若手机号及当前手机号本身以外已存在,提示"手机号已存在"。

我们可以考虑在class PrettyModelForm也就是靓号ModelForm类里添加以下代码:

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

整合之后,可以这样写:

image-20240314120951690

class PrettyModelForm(BootStrapModelForm):# 验证:方式1mobile = forms.CharField(label="手机号",validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'), ],)class Meta:model = models.PrettyNum# fields = "__all__"# exclude = ['level']fields = ["mobile", 'price', 'level', 'status']# 验证:方式2def clean_mobile(self):txt_mobile = self.cleaned_data["mobile"]exists = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()if exists:raise ValidationError("手机号已存在")# 验证通过,用户输入的值返回return txt_mobile

效果:

121

5、删除靓号

与上述步骤相仿,我们继续来实现删除靓号,删除靓号的基础是建立在靓号列表的实现和新增靓号的功能之上的。

1.在urls.py中添加用户列表的路径pretty/<int:nid>/delete/,并告诉该路径指向的视图view.pretty_delete

urls.py

 from django.urls import pathfrom api.views import depart,user,prettyurlpatterns = [# 部门管理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/add/", user.user_add),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),]

2.在views.py中写出对应的函数,发出请求,并返回响应pretty_list.html

views.py

def pretty_delete(request, nid):models.PrettyNum.objects.filter(id=nid).delete()return redirect('/pretty/list/')

3.操作templates目录下模版html文件user_list.html,以此实现用户信息的删除。

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><div style="display: flex; align-items: center"><!-- 页面切换 --><div> <!-- 无需再设置float和宽度 --><ul class="pagination">{{ page_string }}</ul></div><!-- 输入页码框 --><div style="width: 200px;margin-bottom: 5px"> <!-- 保持输入框宽度,但不需要float:right --><form method="get"><div class="input-group"><input type="text" name="page" class="form-control" placeholder="页码"><span class="input-group-btn"><button class="btn btn-default" type="submit">跳转</button></span></div></form></div></div>
{% endblock %}

效果:

image-20240314121746634

整体效果:

122

6、靓号搜索

在实现了上述基础模块功能后,新增一个搜索的功能,那该怎么实现呢?

filter()筛选方法可以帮助我们实现,例如:

# models.PrettyNum.objects.filter()用于从数据库中查询符合特定条件的记录
models.PrettyNum.objects.filter("18812345678",id=123)data_dict = {"mobile":"18821213246","id"=123}
models.PrettyNum.objects.filter(**data_dict)
# 等于12
models.PrettyNum.objects.filter(id=12)
# 大于12
models.PrettyNum.objects.filter(id__gt=12)
# 大于等于12
models.PrettyNum.objects.filter(id__gte=12)
# 小于12
models.PrettyNum.objects.filter(id__lt=12)
# 小于等于12
models.PrettyNum.objects.filter(id__lte=12)data_dict = {"id__lte":12}
models.PrettyNum.objects.filter(**data_dict)
# 筛选出等于152的
models.PrettyNum.objects.filter(mobile="152")
# 筛选出以152开头的
models.PrettyNum.objects.filter(mobile__startwith="152")
# 筛选出以765结尾的
models.PrettyNum.objects.filter(mobile__endswith="765")
# 筛选出包含666的
models.PrettyNum.objects.filter(mobile__contains="666")data_dict = {"mobile_contains":"999"}
models.PrettyNum.objects.filter(**data_dict)

紧接着我们来实现这个功能:

修改views.py视图函数中的pretty_list:

def pretty_list(request):"""靓号列表"""data_dict = {}# 如果是空字典,表示获取所有# 不加后面的 "", 首次访问浏览器,搜索框中不会显示前端页面中的 placeholder="Search for..." 属性search_data = request.GET.get('query', "")if search_data:data_dict["mobile__contains"] = search_dataqueryset = 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_stringhead_page = page_object.head_pageend_page = page_object.end_pagecontext = {"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)

修改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><div style="display: flex; align-items: center"><!-- 页面切换 --><div> <!-- 无需再设置float和宽度 --><ul class="pagination">{{ page_string }}</ul></div><!-- 输入页码框 --><div style="width: 200px;margin-bottom: 5px"> <!-- 保持输入框宽度,但不需要float:right --><form method="get"><div class="input-group"><input type="text" name="page" class="form-control" placeholder="页码"><span class="input-group-btn"><button class="btn btn-default" type="submit">跳转</button></span></div></form></div></div>
{% endblock %}

效果:

123

7、分页切换

要想实现分页跳转切换,要明白它的原理,分页首先要得出总页数,划分好每页的数量,比如10或20,拿总页数除以10或20,最终得到页数,然后再设计跳转的功能,此时比如page=1到page=2,此时我们可以通过操作点击对应的页码,进而实现page+1来实现。在具体实现它之前先了解一些简要的操作,假如每页10个,我们该如何将这10个提取出来?

queryset = models.PrettyNum.objects.all()queryset = models.PrettyNum.objects.filter(id=1)[0:10]
# 第1页
queryset = models.PrettyNum.objects.all()[0:10]
# 第2页
queryset = models.PrettyNum.objects.all()[10:20]
# 第3页
queryset = models.PrettyNum.objects.all()[20:30]
data = models.PrettyNum.objects.all().count()
data = models.PrettyNum.objects.filter(id=1).count()
  • 分页的逻辑和处理规则
def pretty_list(request):# """靓号列表"""# for i in range(300):#     models.PrettyNum.objects.create(mobile="18811899006",price=10,level=1,status=1)data_dict = {}search_data = request.GET.get("q", "")if search_data:data_dict["mobile__contains"] = search_dataqueryset = models.PrettyNum.objects.filter(**data_dict).order_by("-level")page_object = Pagination(request)page_queryset = page_object.page_queryset# 1.根据用户想要访问的页码,计算出起始和终止位置# page = int(request.GET.get('page', 1))# page_size = 10  # 每页显示10条数据# start = (page - 1) * page_size# end = page * page_size# 数据总条数total_count = models.PrettyNum.objects.filter(**data_dict).order_by("-level").count()# 总页码total_page_count, div = divmod(total_count, page_size)if div:total_page_count += 1# 计算出,显示出当前页的前5页和后5页plus = 5if total_page_count <= 2 * plus + 1:# 数据库中的数据比较少,都没有达到11页start_page = 1end_page = total_page_countelse:# 数据库中的数据较多,大于11页# 当前页小于5时(小极值)if page <= plus:start_page = 1end_page = 2 * plus + 1else:# 当前页大于5时# 当前页+5 > 总页面if (page + plus) > total_page_count:start_page = total_page_count - 2 * plusend_page = total_page_countelse:start_page = page - plusend_page = page + plus + 1# 页码page_str_list = []# 首页page_str_list.append('<li><a href="?page={}">首页</a></li>'.format(1))# 上一页if page > 1:prev = '<li><a href="?page={}">上一页</a></li>'.format(page-1)else:prev = '<li><a href="?page={}">上一页</a></li>'.format(1)page_str_list.append(prev)for i in range(start_page, end_page + 1):if i == page: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)# 下一页if page < total_page_count:prev = '<li><a href="?page={}">下一页</a></li>'.format(page+1)else:prev = '<li><a href="?page={}">下一页</a></li>'.format(total_page_count)page_str_list.append(prev)# 首页page_str_list.append('<li><a href="?page={}">尾页</a></li>'.format(total_page_count))page_string = mark_safe("".join(page_str_list))page_number = request.GET.get('page', 1)  # 获取页码,默认为1paginator = Paginator(queryset, 10)  # 假设每页显示10条数据try:page_obj = paginator.page(page_number)except PageNotAnInteger:# 如果页码不是一个整数,则显示第一页page_obj = paginator.page(1)except EmptyPage:# 如果页码超出范围,则显示最后一页page_obj = paginator.page(paginator.num_pages)search_string = """"""page_str_list.append(search_string)return render(request, 'pretty_list.html',{'queryset': queryset, "search_data": search_data, "page_string": page_string,'page_obj': page_obj})

在实现了上述逻辑之后,虽然代码难度不高,但是难免过于繁琐,那么该怎么灵活地利用它呢?

可以对它分页类封装,这样以后再遇到要写分页的时候,我们只需要调用它稍加修改就好:

新建文件夹utils,并新建pagination.py文件以存放它:

image-20240314124021506

pagination.py

"""
自定义的分页组件"""from django.utils.safestring import mark_safe
import copyclass 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 = Trueself.query_dict = query_dictself.page_param = page_parampage = int(request.GET.get(page_param, 1))# 如果不是整数if type(page) != int:# 强制让页码为1page = 1self.page = pageself.start = (page - 1) * page_sizeself.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 += 1self.total_page_count = total_page_count    # 总页码数量self.page_show = page_show  # 当前页前后展示的页码数量self.request = requestdef html(self):# 如果总页码数量大于 11if self.total_page_count > self.page_show * 2 + 1:# 如果当前页面页码位置小于等于5if self.page <= 5:start_page = 1end_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 * 2end_page = self.total_page_count + 1else:# 计算出当前页的前5页和后5页start_page = self.page - self.page_showend_page = self.page + self.page_show + 1else:start_page = 1end_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))

124

8、优化(整合分类)

①拆分views.py

由上面可以看到,上面部分内容有些杂乱,因此我们可以将views.py 换成 views目录,将views.py拆成depart.py、user.py、pretty.py,这样区分更鲜明,更易于管理

1.depart.py

# -*- coding: utf-8 -*-            
# @Time : 2024-03-13 21:39
from django.shortcuts import render, redirect
from api import models
from api.utils.pagination import Paginationdef depart_list(request):"""部门列表"""queryset = models.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')# 获取用户POST提交过来的数据(title输入为空)title = request.POST.get("title")# 保存到数据库models.Department.objects.create(title=title)# 重定向回部门列表return redirect("/depart/list/")def depart_delete(request):"""删除部门"""# 获取ID# http://127.0.0.1:8000/depart/delete/?nid=1nid = request.GET.get('nid')models.Department.objects.filter(id=nid).delete()# 重定向回部门列表return redirect("/depart/list")def depart_edit(request, nid):"""修改部门"""if request.method == "GET":# 根据nid,获取他的数据[obj,]row_object = models.Department.objects.filter(id=nid).first()return render(request, 'depart_edit.html', {"row_object": row_object})# 获取用户的标题title = request.POST.get("title")# 根据ID找到数据库中的数据进行更新models.Department.objects.filter(id=nid).update(title=title)# 重定向回部门列表return redirect("/depart/list/")

2.user.py

# -*- coding: utf-8 -*-            
# @Time : 2024-03-13 21:39
from django.shortcuts import render, redirect
from api import models
from api.models import UserInfo
from api.utils.pagination import Pagination
from api.utils.form import UserModelFormdef user_list(request):"""用户列表"""# 获取所有用户列表queryset = UserInfo.objects.all()page_object = Pagination(request, queryset, page_size=3)# 用 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_add(request):"""添加用户(原始方式)"""if request.method == "GET":context = {'gender_choices': models.UserInfo.gender_choices,'depart_list': models.Department.objects.all(),}return render(request, 'user_add.html', context)# 获取用户提交的数据user = request.POST.get('name')pwd = request.POST.get('pwd')age = request.POST.get('age')account = request.POST.get('ac')ctime = request.POST.get('ctime')gender = request.POST.get('gd')depart_id = request.POST.get('dp')# 添加到数据库中国models.UserInfo.objects.create(name=user, password=pwd, age=age, account=account, creat_time=ctime, gender=gender,depart_id=depart_id)# 返回到用户列表页面return redirect("/user/list/")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):models.UserInfo.objects.filter(id=nid).delete()return redirect('/user/list/')

3.pretty.py

# -*- coding: utf-8 -*-            
# @Time : 2024-03-13 21:39
from django import forms
from django.core.validators import RegexValidator
from django.shortcuts import render, redirect
from api import models
from api.models import PrettyNum, UserInfo
from api.utils.pagination import Pagination
from api.utils.form import UserModelForm, PrettyModelForm, PrettyEditModelFormdef pretty_list(request):"""靓号列表"""data_dict = {}# 如果是空字典,表示获取所有# 不加后面的 "", 首次访问浏览器,搜索框中不会显示前端页面中的 placeholder="Search for..." 属性search_data = request.GET.get('query', "")if search_data:data_dict["mobile__contains"] = search_dataqueryset = 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_stringhead_page = page_object.head_pageend_page = page_object.end_pagecontext = {"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 pretty_add(request):"""添加靓号"""if request.method == "GET":form = PrettyModelForm()return render(request, "pretty_add.html", {"form": form})form = PrettyModelForm(data=request.POST)if form.is_valid():form.save()return redirect('/pretty/list/')return render(request, 'pretty_add.html', {"form": form})def pretty_edit(request, nid):""" 编辑靓号 """row_object = models.PrettyNum.objects.filter(id=nid).first()if request.method == "GET":form = PrettyEditModelForm(instance=row_object)return render(request, 'pretty_edit.html', {"form": form})form = PrettyEditModelForm(data=request.POST, instance=row_object)if form.is_valid():form.save()return redirect('/pretty/list/')return render(request, 'pretty_edit.html', {"form": form})def pretty_delete(request, nid):models.PrettyNum.objects.filter(id=nid).delete()return redirect('/pretty/list/')

新手保护期,views可拆分,尽量先别拆models.py,一般平时够用。

②ModelForm优化

将三个单独定义的类

class UserModelForm(forms.ModelForm):
class PrettyModelForm(forms.ModelForm):
class PrettyEditModelForm(forms.ModelForm):

改为继承自同一个自定义类,这样做的好处在于,以后再有其它类,常规的部分不需要再重复定义,直接从父类获取即可:

class UserModelForm(BootStrapModelForm):
class PrettyModelForm(BootStrapModelForm):
class PrettyEditModelForm(BootStrapModelForm):

将自定义类放在utils目录下新建的bootstrap.py中:

class BootStrapModelForm(forms.ModelForm):def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)# 循环ModelForm中的所有字段,给每个字段的插件设置for name, field in self.fields.items():# 字段中有属性,保留原来的属性,没有属性,才增加。if field.widget.attrs:field.widget.attrs["class"] = "form-control"field.widget.attrs["placeholder"] = field.labelelse:field.widget.attrs = {"class": "form-control","placeholder": field.label}

③整合Form

将三个类整合到一起,放在utils目录下新建的form.py中

from api import models
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from django import forms
from api.utils.bootstrap import BootStrapModelFormclass UserModelForm(BootStrapModelForm):name = forms.CharField(min_length=3,label="用户名",widget=forms.TextInput(attrs={"class": "form-control"}))class Meta:model = models.UserInfofields = ["name", "password", "age", 'account', 'creat_time', "gender", "depart"]class PrettyModelForm(BootStrapModelForm):# 验证:方式1mobile = forms.CharField(label="手机号",validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'), ],)class Meta:model = models.PrettyNum# fields = "__all__"# exclude = ['level']fields = ["mobile", 'price', 'level', 'status']# 验证:方式2def clean_mobile(self):txt_mobile = self.cleaned_data["mobile"]exists = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()if exists:raise ValidationError("手机号已存在")# 验证通过,用户输入的值返回return txt_mobileclass PrettyEditModelForm(BootStrapModelForm):# mobile = forms.CharField(disabled=True, label="手机号")mobile = forms.CharField(label="手机号",validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误'), ],)class Meta:model = models.PrettyNumfields = ['mobile', 'price', 'level', 'status']# 验证:方式2def clean_mobile(self):# 当前编辑的哪一行的ID# print(self.instance.pk)txt_mobile = self.cleaned_data["mobile"]exists = models.PrettyNum.objects.exclude(id=self.instance.pk).filter(mobile=txt_mobile).exists()if exists:raise ValidationError("手机号已存在")# 验证通过,用户输入的值返回return txt_mobile

效果:

125

优化后,仍然能达到相同的效果,区别在于,后者更加整齐,分类更清晰。

关于靓号管理的实现就到这里,后续会继续实现管理员管理、账户登录、以及Ajax等,并及时更新博客,敬请期待。

很感谢你能看到这里,如有相关疑问,还请下方评论留言。
Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)
希望本篇内容能对大家有所帮助,如果大家喜欢的话,请动动手点个赞和关注吧,非常感谢你们的支持!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/745607.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue手写模拟步骤条

效果图&#xff1a; 如果要使用element的步骤条就需要强行修改样式&#xff0c;参考之前的那篇步骤条。这里我采用手写div 代码&#xff1a; 思路是给最外层的div一个左边框&#xff0c;给里面的step-item设置左边框为图片&#xff0c;通过定位来移动。 <div class"m…

Canal实现mysql与缓存同步

什么是Canal Canal是阿里巴巴旗下的一款开源项目, 基于java开发. Canal是基于mysql的主从同步来实现的. github地址: https://github.com/alibaba/canal Canal把自己伪装成MySQL的一个slave节点, 从而监听master的binary log变化. 再把得到的变化信息通知给Canal的客户端, 进而…

个人简历主页搭建系列-02:github 仓库作为联系方式

这篇文章暂时没有开始正式搭建网站。首先是最重要的注意事项&#xff1a;隐私。 真实姓名如果大家自己不介意的话其实我觉得还好&#xff0c;现在在互联网上想扒个姓名挺简单的&#xff0c;而且很多人都实名上网hh&#xff08;比如我的几位田径队学弟笑&#xff09;。 电话&a…

小程序学习3 goods-card

pages/home/home home.wxml <goods-listwr-class"goods-list-container"goodsList"{{goodsList}}"bind:click"goodListClickHandle"bind:addcart"goodListAddCartHandle"/> <goods-list>是一个自定义组件&#xff0c;它具…

[抽象]工厂模式([Abstract] Factory)——创建型模式

[抽象]工厂模式——创建型模式 什么是抽象工厂&#xff1f; 抽象工厂模式是一种创建型设计模式&#xff0c;让你能够保证在客户端程序中创建一系列有依赖的对象组时&#xff0c;无需关心这些对象的类型。 具体来说&#xff1a; 对象的创建与使用分离&#xff1a; 抽象工厂模…

信号与系统学习笔记——信号的分类

目录 一、确定与随机 二、连续与离散 三、周期与非周期 判断是否为周期函数 离散信号的周期 结论 四、能量与功率 定义 结论 五、因果与反因果 六、阶跃函数 定义 性质 七、冲激函数 定义 重要关系 作用 一、确定与随机 确定信号&#xff1a;可以确定时间函数…

uniapp移动端 IOS系统下无法与webview通信

不知道有没有人遇到过这个问题 我的页面嵌套了一个webview&#xff08;文件位于项目的hybrif/html&#xff09;目录下 使用evalJS与webview进行通信 代码如下 在安卓里运行是没问题的&#xff0c;但在苹果手机上一直无法通信 连接真机&#xff0c;打印evalJS是个方法&#xf…

C语言中内存函数的使用

memcpy函数的使用和模拟实现 memcpy的使用 函数使用说明&#xff1a; • 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。 • 这个函数在遇到 \0 的时候并不会停下来。 • 如果source和destination有任何的重叠&#xff0c;复制的结…

【python】centos 8新装python3.10.0

1.python源码包准备 2.gcc环境安装 如果系统已具备&#xff0c;可以略过。 有的已经自带了gcc&#xff0c;但是如果编译时启动优化的话&#xff0c;如果gcc版本过老就必须要升级。 3.make环境安装 如果系统已具备&#xff0c;可以略过。 4.更新openssl版本&#xff08;很重…

C# 根据两点名称,寻找两短路程的最优解,【有数据库设计,完整代码】

前言 如果我们遇到路径问题&#xff0c;可以使用点点连线&#xff0c;给定一个点&#xff0c;可以到达另外几个点&#xff0c;寻找最优解 例&#xff1a;如下图所示&#xff0c;如果要从A1-C1,可以有三条路 1.A1-B1-C1 2.A1-B2-C1 3.A1-B3-C1 最优解肯定是A1-B1-C1&#xff0c…

Java代码审计安全篇-XXE(XML外部实体注入)漏洞

前言&#xff1a; 堕落了三个月&#xff0c;现在因为被找实习而困扰&#xff0c;着实自己能力不足&#xff0c;从今天开始 每天沉淀一点点 &#xff0c;准备秋招 加油 注意&#xff1a; 本文章参考qax的网络安全java代码审计&#xff0c;记录自己的学习过程&#xff0c;还希望各…

软考77-上午题-【面向对象技术3-设计模式】-创建型设计模式02

一、生成器模式 1-1、意图 将一个复杂对象的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 1-2、结构图 Builder 为创建一个 Product 对象的各个部件指定抽象接口。ConcreteBuilder 实现 Builder 的接口以构造和装配该产品的各个部件&#xff0c;定…

css设置选中文字和选中图片字的颜色

要改变页面中选中文字的颜色&#xff0c;可以使用 CSS 的 ::selection 伪元素来实现 *::selection {/* 改变选中文字的背景色 */background-color: #c42121;/* 改变选中文字的文本颜色 */color: #fff; } 用通配符选择器给所有元素都加上了 ::selection伪元素&#xff0c;用于…

GPT实战系列-如何让LangChain的Agent选择工具

GPT实战系列-如何让LangChain的Agent选择工具 LangChain GPT实战系列-LangChain如何构建基通义千问的多工具链 GPT实战系列-构建多参数的自定义LangChain工具 GPT实战系列-通过Basetool构建自定义LangChain工具方法 GPT实战系列-一种构建LangChain自定义Tool工具的简单方法…

先验分布、后验分布、极大似然的一点思考

今天和组里同事聊天的时候&#xff0c;无意中提到了贝叶斯统计里先验分布、后验分布、以及极大似然估计这三个概念。同事专门研究如何利用条件概率做系统辨识的&#xff0c;给我画了一幅图印象非常深刻&#xff1a; 其中k表示时序关系。上面这个图表示后验分布是由先验分布与似…

2024年云服务器ECS价格表出炉——阿里云

2024年阿里云服务器租用费用&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元&#xff0c;ECS u1服务器2核4G5M固定带宽199元一年&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;2核4G服务…

深入理解TCP的四次分手过程

文章目录 深入理解TCP的四次分手过程四次分手的意义四次分手的工作原理四次分手的重要性实际应用中的考虑结论补充:TIME_WAIT在哪一步?TIME_WAIT状态的目的TIME_WAIT状态的影响 深入理解TCP的四次分手过程 在网络通信中&#xff0c;TCP&#xff08;传输控制协议&#xff09;确…

在Linux/Ubuntu/Debian中使用7z压缩和解压文件

要在 Ubuntu 上使用 7-Zip 创建 7z 存档文件&#xff0c;你可以使用“7z”命令行工具。 操作方法如下&#xff1a; 安装 p7zip&#xff1a; 如果你尚未在 Ubuntu 系统上安装 p7zip&#xff08;7-Zip 的命令行版本&#xff09;&#xff0c;你可以使用以下命令安装它&#xff1a;…

Gitlab光速发起Merge Request

前言 在我们日常开发过程中需要经常使用到Merge Request&#xff0c;在使用过程中我们需要来回在开发工具和UI界面之前来回切换&#xff0c;十分麻烦。那有没有一种办法可以时间直接开发开工具中直接发起Merge Request呢&#xff1f; 答案是有的。 使用 Git 命令方式创建 Me…

Unity资源热更新----AssetBundle

13.1 资源热更新——AssetBundle1-1_哔哩哔哩_bilibili Resources 性能消耗较大 Resources文件夹大小不能超过2个G 获取AssetBundle中的资源 打包流程 选择图片后点击 创建文件夹&#xff0c;Editor优先编译 打包文件夹位置 using UnityEditor; using UnityEngine; public cla…