1.靓号管理
1.1 表结构
根据表结构的需求,在models.py中创建类(由类生成数据库中的表)。
class PrettyNum(models.Model):
""" 靓号表 """
mobile = models.CharField(verbose_name="手机号", max_length=11)
# 想要允许为空 null=True, blank=True
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)
自己在数据模拟创建一些数据:
insert into app01_prettynum(mobile,price,level,status)values("111111111",19,1,1);
1.2 靓号列表
- URL
- 函数
- 获取所有靓号
- 结合HTML+render将靓号罗列出来
id 号码 价格 级别(中文) 状态(中文)
pretty_list.html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div style="margin-bottom: 10px">
<a class="btn btn-success" href="#">
<span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
新建靓号
</a>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
用户列表
</div>
<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 queryset %}
<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="#">编辑</a>
<a class="btn btn-danger btn-xs" href="#">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
layout.html里面添加如下图
1.3 新建靓号
-
列表页面跳转:
/pretty/add/
-
URL
-
ModelForm类
from django import forms class PrettyModelForm(forms.ModelForm): ...
-
函数
- 实例化类的对象
- 通过render将对象传入到HTML中。
- 模板的循环展示所有的字段。
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><span style="font-weight:bold;">新建靓号</span></h3>
</div>
<div class="panel-body">
<form method="post" novalidate> # 如果没写novalidate浏览器会做校验
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<labe><span style="font-weight:bold;">{{ field.label }}</span></labe>
{{ field }}
<span style="color: red">{{ field.errors.0 }}</span>
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">提交</button>
</form>
</div>
</div>
</div>
{% endblock %}
- 点击提交
- 数据校验
- 保存到数据库
- 跳转回靓号列表
可以为空,输入也能提交但是这样需要格式校验(手机号11位)
1.4 编辑靓号
- 列表页面:`/pretty/数字/edit/
- URL
- 函数
- 根据ID获取当前编辑的对象
- ModelForm配合,默认显示数据。
- 提交修改。
不允许手机号重复
- 添加:【正则表达式】【手机号不能存在】
# [obj,obj,obj] 对象
queryset = models.PrettyNum.objects.filter(mobile="1888888888")
obj = models.PrettyNum.objects.filter(mobile="1888888888").first()
# True/False
exists = models.PrettyNum.objects.filter(mobile="1888888888").exists() # 钩子方法里面操作
- 编辑:【正则表达式】【手机号不能存在】
排除自己以外,其他的数据是否手机号是否重复?
# id!=2 and mobile='1888888888'
models.PrettyNum.objects.filter(mobile="1888888888").exclude(id=2)
1.5 删除靓号
1.6 搜索手机号
models.PrettyNum.objects.filter(mobile="19999999991",id=12)
data_dict = {"mobile":"19999999991","id":123}
models.PrettyNum.objects.filter(**data_dict) #如果在filter里面放了空字典就相当于获取所有的
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) # 小于等于12
data_dict = {"id__lte":12}
models.PrettyNum.objects.filter(**data_dict)
models.PrettyNum.objects.filter(mobile="999") # 等于
models.PrettyNum.objects.filter(mobile__startswith="1999") # 筛选出以1999开头
models.PrettyNum.objects.filter(mobile__endswith="999") # 筛选出以999结尾
models.PrettyNum.objects.filter(mobile__contains="999") # 筛选出包含999
data_dict = {"mobile__contains":"999"}
models.PrettyNum.objects.filter(**data_dict)
1.7 分页
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]
- 分页的逻辑和处理规则
- 封装分页类
- 从头到尾开发
- 写项目用【pagination.py】公共组件。
pagination.py
"""
自定义的分页组件,以后如果想要使用这个分页组件,你需要做如下几件事:
在视图函数中:
def pretty_list(request):
# 1.根据自己的情况去筛选自己的数据
queryset = models.PrettyNum.objects.all()
# 2.实例化分页对象
page_object = Pagination(request, queryset)
context = {
"queryset": page_object.page_queryset, # 分完页的数据
"page_string": page_object.html() # 生成页码
}
return render(request, 'pretty_list.html', context)
在HTML页面中
{% for obj in queryset %}
{{obj.xx}}
{% endfor %}
<ul class="pagination">
{{ page_string }}
</ul>
"""
from django.utils.safestring import mark_safe
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: 显示当前页的 前或后几页(页码)
"""
from django.http.request import QueryDict
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")
if page.isdecimal():
page = int(page)
else:
page = 1
self.page = page
self.page_size = page_size
self.start = (page - 1) * page_size
self.end = page * page_size
self.page_queryset = queryset[self.start:self.end]
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
pretty_list.html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div style="margin-bottom: 10px" class="clearfix">
<a class="btn btn-success" href="/pretty/add/">
<span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
新建靓号
</a>
<div style="float: right;width: 300px;">
<form method="get">
<div class="input-group">
<input type="text" name="q" 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 class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true"></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 queryset %}
<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 class="clearfix">
<ul class="pagination">
{{ page_string }}
</ul>
</div>
</div>
{% endblock %}
修改以下用户管理分页
修改部门管理分页
1.7.1 分页的关键步骤
1.8 时间插件
<link rel="stylesheet" href="static/plugins/bootstrap-3.4.1/css/bootstrap.css">
<link rel="stylesheet" href="static/plugins/bootstrap-datepicker/css/bootstrap-datepicker.css">
<input type="text" id="dt" class="form-control" placeholder="入职日期">
<script src="static/js/jquery-3.6.0.min.js"></script>
<script src="static/plugins/bootstrap-3.4.1/js/bootstrap.js"></script>
<script src="static/plugins/bootstrap-datepicker/js/bootstrap-datepicker.js"></script>
<script src="static/plugins/bootstrap-datepicker/locales/bootstrap-datepicker.zh-CN.min.js"></script>
<script>
$(function () {
$('#dt').datepicker({
format: 'yyyy-mm-dd',
startDate: '0',
language: "zh-CN",
autoclose: true
});
})
</script>
在ModelForm界面:
1.9 优化ModelForm和BootStrap
- ModelForm可以帮助我们生成HTML标签。
例如:
class UserModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = ["name", "password",]
form = UserModelForm()
在HTML中只是生成了普通的input框没有bootstrap样式:
{{form.name}} 普通的input框
{{form.password}} 普通的input框
- 定义插件
class UserModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = ["name", "password",]
widgets = {
"name": forms.TextInput(attrs={"class": "form-control"}),
"password": forms.PasswordInput(attrs={"class": "form-control"}),
"age": forms.TextInput(attrs={"class": "form-control"}),
}
也可以这样写:
class UserModelForm(forms.ModelForm):
name = forms.CharField(
min_length=3,
label="用户名",
widget=forms.TextInput(attrs={"class": "form-control"})
)
class Meta:
model = models.UserInfo
fields = ["name", "password", "age"]
在HTML展示是可以有bootstrap样式的
{{form.name}} BootStrap的input框
{{form.password}} BootStrap的input框
问题在于这么写太繁琐了,所有我们重新定义init方法
- 重新定义的init方法,批量设置
class UserModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = ["name", "password", "age",]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环ModelForm中的所有字段,给每个字段的插件设置
for name, field in self.fields.items():
field.widget.attrs = {
"class": "form-control",
"placeholder": field.label
}
优化:
class UserModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = ["name", "password", "age",]
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.label
else:
field.widget.attrs = {
"class": "form-control",
"placeholder": field.label
}
再优化:
自定义类
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.label
else:
field.widget.attrs = {
"class": "form-control",
"placeholder": field.label
}
让它继承:
class UserEditModelForm(BootStrapModelForm):
class Meta:
model = models.UserInfo
fields = ["name", "password", "age",]
1.9.1 操作
- 提取公共的类
- 在
vews.py
中找到所有的modelform
继承并拆分出来
- 将
vews.py
文件中的业务按照类型拆分斌删除vews.py
文件
- 关键点:修改urls.py文件