员工管理系统:编辑用户、删除用户、靓号增删改查、分页功能实现、封装分页功能、第三方时间组件的使用
- 部门管理
- 用户管理
- 用户列表
- 新建用户
- ModelForm:针对数据库中的某个表
- Form。
1. 编辑用户
点击编辑,跳转到编辑页面(将编辑行的ID携带过去)
编辑页面显示默认数据(根据ID获取并设置到页面中)
提交
- 错误提示
- 数据校验
- 在数据库更新
models.UserInfo.filter(id=4).update(...)
def user_edit(request, nid):
""" 编辑用户 """
row_object = models.UserInfo.objects.filter(id=nid).first()
if request.method == "GET":
# 根据ID去数据库获取编辑的那一行数据
form = UserModelForm(instance=row_object)
return render(request, 'user_edit.html', {'form':form})
form = UserModelForm(data=request.POST, instance=row_object)
if form.is_valid():
# 默认保存的是用户输入的所有数据;如果想要在用户输入的数据以外增加一些参数值
# form.instance.字段名 = 值
form.save()
return redirect('/user/list/')
return render(request, 'user_edit.html', {'form':form})
2. 删除用户
def user_delete(request, nid):
models.UserInfo.objects.filter(id=nid).delete()
return redirect('/user/list/')
3. 靓号管理
3.1 数据库表结构
ID | mobile | price | level(级别 Choices) | status(状态:1未占用/2已占用) |
---|
- 根据表结构的需求,在models.py中创建类,由类生成数据库中的表
class PrettyNum(models.Model):
""" 靓号表 """
# 想要允许为空: null = True, blank = True
mobile = models.CharField(verbose_name="手机号", max_length=11)
price = models.IntegerField(verbose_name="价格", default=100)
level_choices = (
(1, "1级"),
(2, "2级"),
(3, "3级"),
(4, "4级"),
(5, "5级"),
)
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("11112345678", 1000, 1, 2);
3.2 靓号列表
- URL
- 函数
- 获取所有靓号
- 结合HTML+render将靓号罗列出来
ID 号码 价格 级别 状态 操作
def pretty_num_list(request):
""" 靓号列表 """
pretty_num_list_data = models.PrettyNum.objects.all().order_by('-level')
return render(request, 'pretty_num_list.html', {'pretty_num_list_data':pretty_num_list_data})
3.3 新建靓号
列表页面点击跳转
URL
ModelForm类
from django import form
# 需要先导入 form
class PrettyModelForm(forms.ModelForm):
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
class PrettyNumModelForm(forms.ModelForm):
# name = forms.CharField(min_length=3, label="姓名")
""" 方式一:验证手机号格式是否正确(字段+正则)"""
# mobile = forms.CharField(
# label="手机号",
# # validators=[RegexValidator(r'^1\d{10}$', '格式错误,请输入正确手机号')]
# validators=[RegexValidator(r'^1[3-9]\d{9}$', '格式错误,请输入正确手机号')]
# )
class Meta:
model = models.PrettyNum
fields = ["mobile", "price", "level", "status"]
# fields = "__all__" 所有字段
# exclude = ['level'] 排除该字段
# widgets = {
# 'name': forms.TextInput(attrs={'class':'form-control', 'placeholder':'请输入内容'}),
# 'password': forms.PasswordInput(attrs={'class':'form-control', 'placeholder':'请输入内容'}),
# }
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name,field in self.fields.items():
field.widget.attrs = {'class': 'form-control', 'placeholder': '请输入内容'}
""" 方式二:验证手机号格式是否正确(钩子)"""
def clean_mobile(self):
txt_mobile = self.cleaned_data["mobile"]
if len(txt_mobile) != 11:
raise ValidationError("手机号长度不正确,请重新输入")
return txt_mobile
- 函数
- 实例化类的对象
- 通过render将对象传入到HTML中
- 模板的循环展示所有字段值
- 点击提交
- 数据校验
- 保存到数据库
- 跳转回靓号列表
"""
添加靓号
"""
def pretty_num_add(request):
if request.method == "GET":
form = PrettyNumModelForm()
return render(request, 'pretty_num_add.html', {'form':form})
form = PrettyNumModelForm(data=request.POST)
if form.is_valid():
form.save()
return redirect('/pretty/num/list/')
return render(request, 'pretty_num_add.html', {'form':form})
3.4 编辑靓号
- 列表页面:
pretty/num/ID(数字)/edit
- URL
- 函数
- 根据ID获取当前编辑的对象
- ModelForm配合,默认显示编辑前的数据
- 提交修改
不允许手机号重复
- 添加【正则表达式】【手机号不能重复】
queryset = models.PrettyNum.objects.filter(mobile="xxx")
queryset = models.PrettyNum.objects.filter(mobile="xxx").first()
# True/False [判断是否已存在]
queryset = models.PrettyNum.objects.filter(mobile="xxx").exists()
- 编辑【正则表达式】【手机号不能重复】
# 排除自己以外,判断其他的数据中手机号是否重复
# id!=2 and mobile="xxx"
models.PrettyNum.objects.filter(mobile="xxx").exclude(id=2)
class PrettyNumEditModelForm(forms.ModelForm):
mobile = forms.CharField(
label="手机号",
validators=[RegexValidator(r'^1[3-9]\d{9}$', '格式错误,请输入正确手机号')],
# disabled=True,
)
class Meta:
model = models.PrettyNum
fields = ["mobile", "price", "level", "status"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name,field in self.fields.items():
field.widget.attrs = {'class': 'form-control', 'placeholder': '请输入内容'}
def clean_mobile(self):
# 当前编辑的那一行的ID
# self.instance.pk
txt_mobile = self.cleaned_data["mobile"]
exists = models.PrettyNum.objects.exclude(id=self.instance.id).filter(mobile=txt_mobile).exists()
if exists:
raise ValidationError("手机号已存在,请重新输入")
return txt_mobile
"""
编辑靓号
"""
def pretty_num_edit(request, nid):
row_object = models.PrettyNum.objects.filter(id=nid).first()
if request.method == "GET":
form = PrettyNumEditModelForm(instance=row_object)
return render(request, 'pretty_num_edit.html', {'form':form})
form = PrettyNumEditModelForm(data=request.POST, instance=row_object)
if form.is_valid():
form.save()
return redirect('/pretty/num/list')
return render(request, 'pretty_num_edit.html', {'form': form})
3.5 搜索手机号
models.PrettyNum.objects.filter(mobile="xxx", id=16)
# 传入空字典时,相当于获取所有的数据
data_dict = {"mobile":"xxx", "id":15}
models.PrettyNum.objects.filter(**data_dict)
models.PrettyNum.objects.filter(id=16) # id=xx
models.PrettyNum.objects.filter(id__gt=16) # id>xx
models.PrettyNum.objects.filter(id__gte=16) # id>=xx
models.PrettyNum.objects.filter(id__lt=16) # id<xx
models.PrettyNum.objects.filter(id__lte=16) # id<=xx
models.PrettyNum.objects.filter(mobile="xxx") # mobile=xxx
models.PrettyNum.objects.filter(mobile__startswith="xxx") # mobile以xxx开头
models.PrettyNum.objects.filter(mobile__endswith="xxx") # mobile以xxx结尾
models.PrettyNum.objects.filter(mobile__contains="xxx") # mobile包含xxx
# 综合使用
data_dict = {
"mobile__startswith":"xxx",
"id__lt":15,
}
models.PrettyNum.objects.filter(**data_dict)
- 实例
"""
靓号列表
"""
def pretty_num_list(request):
# 定义一个空字典,如果获取到了q参数值,则传入进行查询;否则传入空字典
# 传入空字典时表示查询所有数据
data_dict = {}
search_data = request.GET.get('q', '')
if search_data:
data_dict["mobile__contains"] = search_data
# 根据level降序排序
pretty_num_list_data = models.PrettyNum.objects.filter(**data_dict).order_by('-level')
return render(request, 'pretty_num_list.html', {'pretty_num_list_data':pretty_num_list_data, 'search_data':search_data})
<div style="margin-bottom: 20px" class="clearfix">
<a href="/pretty/num/add/" class="btn btn-success">
<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="请输入手机号..."
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>
3.6 列表分页
models.PrettyNum.objects.all()
# 数据结果切片
models.PrettyNum.objects.filter(id__gt=16)[0:10]
models.PrettyNum.objects.all()[0:10]
def pretty_num_list(request):
# 定义一个空字典,如果获取到了q参数值,则传入进行查询;否则传入空字典
# 传入空字典时表示查询所有数据
data_dict = {}
search_data = request.GET.get('q', '')
if search_data:
data_dict["mobile__contains"] = search_data
# 1.根据用户想要访问的页码,计算出起止位置
page = int(request.GET.get('page', 1))
page_size = 15 # 每页显示的数据条数
start_page = (page - 1) * page_size
end_page = page * page_size
# 数据总条数
data_count = models.PrettyNum.objects.filter(**data_dict).order_by('-level').count()
# 计算出总页码
total_page_count, div = divmod(data_count, page_size)
if div:
total_page_count += 1
# 根据level降序排序;并切片查询出指定数量的数据
pretty_num_list_data = models.PrettyNum.objects.filter(**data_dict).order_by('-level')[start_page:end_page]
# 计算出 显示当前页的前5页、后5页
plus = 5 # 前N页
if total_page_count <= plus * 2 + 1:
# 数据库中的数据比较少时,都没有达到plus*2+1页
start_page_num = 1
end_page_num = total_page_count
else:
# 数据库中的数据比较多时,>plus*2+1页
# 当前页<5时(小极值)
if page <= plus:
start_page_num = 1
end_page_num = plus * 2 + 1
else:
# 当前页>5时(大极值)
if (page + plus) > total_page_count:
start_page_num = total_page_count - plus * 2
end_page_num = total_page_count
else:
start_page_num = page - plus
end_page_num = page + plus
# 页码
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_num, end_page_num + 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))
# 告诉浏览器该字符串可信/安全 mark_safe
page_string = mark_safe("".join(page_str_list))
return render(request, 'pretty_num_list.html',
{'pretty_num_list_data': pretty_num_list_data, 'search_data': search_data, "page_string": page_string})
4. 分页组件的封装
Pagination —> 公共组件
"""
自定义的分页组件,以后如果想要使用这个分页组件,需要做如下几件事:
(1) 在视图函数中:
def pretty_num_list(request):
# 1. 根据自己的情况去筛选自己想要的数据
pretty_num_list_data = models.PrettyNum.objects.all()
# 2. 实例化分页对象
page_object = Pagination(request, pretty_num_list_data)
# 3. 创建字典,获取数据
context = {
'search_data': search_data,
'pretty_num_list_data': page_object.page_queryset, # 分完页的数据
"page_string": page_object.html(), # 生成页码
}
# 4. 返回相关内容
return render(request, 'pretty_num_list.html', context)
(2) 在HTML中:
{% for obj in pretty_num_list_data %}
{{obj.xxx}}
{% 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中传递的获取分页的参数, 例如: /pretty/list/?page=12
:param plus: 显示当前页的 前或后n页 (页码)
"""
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")
# 如果输入的不是数字,则赋值为1,即初始页面第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页
# 前N页
if self.total_page_count <= self.plus * 2 + 1:
# 数据库中的数据比较少时,都没有达到plus*2+1页
start_page_num = 1
end_page_num = self.total_page_count
else:
# 数据库中的数据比较多时,>plus*2+1页
# 当前页<5时(小极值)
if self.page <= self.plus:
start_page_num = 1
end_page_num = self.plus * 2 + 1
else:
# 当前页>5时(大极值)
if (self.page + self.plus) > self.total_page_count:
start_page_num = self.total_page_count - self.plus * 2
end_page_num = self.total_page_count
else:
start_page_num = self.page - self.plus
end_page_num = 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_num, end_page_num + 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 method="get" style="float: left; margin-left: 20px">
<input
name="page"
style="
position: relative;
float: left;
display: inline-block;
width: 160px;
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)
# 告诉浏览器该字符串可信/安全 mark_safe
page_string = mark_safe("".join(page_str_list))
return page_string
5. 时间选择组件
- 引入css
- 引入js
详情见employeeManage –> user_add.html、user_model_form_add.html