1.编辑用户(基于modelform)
点击编辑,跳转到编辑界面(将编辑行的id携带过去)
编辑页面(默认数据,根据id获取并设置页面中)
提交:错误提示,数据校验,在数据库更新
urls.py
path('user/<int:nid>/edit/', views.user_edit),
views.py
def user_edit(request, nid):
""" 基于modelform版本的用户编辑 """
row_object = UserInfo.objects.filter(id=nid).first()
if request.method == 'GET':
# 根据id去数据库去获取要编辑的那一行的数据
form = UserModelForm(instance=row_object)
return render(request, "user_edit.html", {'form': form})
# 使用post提交数据,数据校验
form = UserModelForm(data=request.POST, instance=row_object)
if form.is_valid():
form.save()
return redirect('/user/list/')
# 校验失败,在页面显示错误信息
return render(request, 'user_edit.html', {'form': form})
user_edit.html
{% extends 'layout.html'%}
{% block content %}
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">编辑用户</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-success">提交</button>
</form>
</div>
</div>
</div>
{% endblock %}
2.删除用户
urls.py
path('user/<int:nid>/delete/', views.user_delete),
views.py
def user_delete(request, nid):
UserInfo.objects.filter(id=nid).delete()
return redirect('/user/list/')
3.靓号管理
3.1创建表结构
models.py
class PrettyNum(models.Model):
""" 靓号表 """
mobile = models.CharField(verbose_name='手机号', max_length=11)
price = models.DecimalField(verbose_name='价格', max_digits=10, decimal_places=2, default=0)
level_choice = (
(1, '1级'),
(2, '2级'),
(3, '3级'),
(4, '4级')
)
level = models.SmallIntegerField(verbose_name='等级', choices=level_choice, default=1)
status_choice = (
(1, '已占用'),
(2, '未占用')
)
status = models.SmallIntegerField(verbose_name='状态', choices=status_choice, default=2)
创建一些数据
mysql -u root -p
use db2;
insert into app01_prettynum(mobile, price, level, status) values('11111111111', 19, 1, 1);
3.2靓号列表
urls.py
path('num/list/', views.num_list),
views.py
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div style="margin-bottom: 10px">
<a class="btn btn-success" href="#">
<span class="glyphicon glyphicon-edit" 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>
{# <div class="panel-body">#}
{# Panel content#}
{# </div>#}
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>ID</th>
<th>电话号</th>
<th>价格</th>
<th>等级</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in data_list %}
<tr>
<td>{
{ obj.id }}</td>
<td>{
{ obj.mobile }}</td>
<td>{
{ obj.price }}</td>
<td>{
{ obj.get_level_display }}</td>
<td>{
{ obj.get_status_display }}</td>
<td>
<a href="#" class="btn btn-primary btn-xs">编辑</a>
<a href="#" class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
num_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-edit" 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>
{# <div class="panel-body">#}
{# Panel content#}
{# </div>#}
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>ID</th>
<th>电话号</th>
<th>价格</th>
<th>等级</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in data_list %}
<tr>
<td>{
{ obj.id }}</td>
<td>{
{ obj.mobile }}</td>
<td>{
{ obj.price }}</td>
<td>{
{ obj.get_level_display }}</td>
<td>{
{ obj.get_status_display }}</td>
<td>
<a href="#" class="btn btn-primary btn-xs">编辑</a>
<a href="#" class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
3.3新建靓号
列表点击【添加靓号】跳转到/num/add/
创建NumModel类
def num_add函数:
GET:示例化类的对象,通过render将对象传入html中,使用模板循环显示所有的字段。
POST:点击提交,数据校验,保存到数据库,跳转到/num/list/
urls.py
path('num/add/', views.num_add),
views.py
from django.core.validators import RegexValidator, ValidationError
class NumModelForm(forms.ModelForm):
# 验证方式1
mobile = forms.CharField(
label='手机号',
validators=[RegexValidator(r'^1[3-9]\d{9}$', '手机号格式错误')]
)
class Meta:
model = PrettyNum
# fields = ['mobile', 'price', 'level', 'status']
# 排除某些字段
# exclude = ['level']
# 展示全部字段
fields = "__all__"
def __init__(self, *args, **kwarg):
super().__init__(*args, **kwarg)
for num, field in self.fields.items():
# 循环找到所有的插件
field.widget.attrs = {'class': 'form-control', 'placeholder': field.label}
# 验证方式2
def clean_mobile(self):
txt_mobile = self.cleaned_data['mobile']
exists = PrettyNum.objects.filter(mobile=txt_mobile).exists()
if exists:
raise ValidationError("手机号已存在")
return txt_mobile
num_add.html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">新建靓号</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-success">提交</button>
</form>
</div>
</div>
</div>
{% endblock %}
3.4编辑靓号
num_list.html添加:href="/num/{ { obj.id }}/edit/"
urls.py添加:path('num//edit/', views.num_edit),
创建NumEditModelForm类(不允许编辑手机号)
num_edit函数
GET:根据id获取当前编辑的对象
POST:提交修改
urls.py
path('num/<int:nid>/edit/', views.num_edit),
views.py
class NumEditModelForm(forms.ModelForm):
# 不允许修改手机号
mobile = forms.CharField(disabled=True, label='手机号')
class Meta:
model = 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": field.label}
def num_edit(request, nid):
""" 靓号编辑 ModelForm """
row_object = PrettyNum.objects.filter(id=nid).first()
if request.method == "GET":
form = NumEditModelForm(instance=row_object)
return render(request, "num_edit.html", {"form": form})
form = NumEditModelForm(data=request.POST, instance=row_object)
if form.is_valid():
form.save()
return redirect('/num/list/')
return render(request, 'num_edit.html', {'form': form})
num_edit.html
{% extends 'layout.html'%}
{% block content %}
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">编辑靓号</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-success">提交</button>
</form>
</div>
</div>
</div>
{% endblock %}
如果此时,允许修改电话号码(即删除mobile = forms.CharField(disabled=True, label='手机号')这一句),此时如何验证手机号码和数据库里的其他数据不重复呢?还是在类NumEditModelForm里写一个函数clean_mobile()
class NumEditModelForm(forms.ModelForm):
# 不允许修改手机号
# mobile = forms.CharField(disabled=True, label='手机号')
class Meta:
model = 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": field.label}
def clean_mobile(self):
# 当前编辑的一行数据的id
print(self.instance.pk)
txt_mobile = self.cleaned_data['mobile']
exists = PrettyNum.objects.exclude(id=self.instance.pk).filter(mobile=txt_mobile).exists()
if exists:
raise ValidationError("手机号已存在")
return txt_mobile
3.5删除靓号
urls.py
path('num/<int:nid>/delete/', views.num_delete),
views.py
def num_delete(request, nid):
PrettyNum.objects.filter(id=nid).delete()
return redirect('/num/list/')
3.6搜索电话号码
views.py
def num_list(request):
""" 靓号列表 """
data_dict = {}
search_data = request.GET.get("q", "")
if search_data:
data_dict["mobile__contains"] = search_data
# 去数据库中获取所有的靓号列表(降序排列)
queryset = PrettyNum.objects.filter(**data_dict).order_by("-level")
return render(request, 'num_list.html', {"data_list": queryset, "search_data": search_data})
num_list.html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div style="margin-bottom: 10px" class="clearfix">
<a class="btn btn-success" href="/num/add/">
<span class="glyphicon glyphicon-edit" 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><!-- /input-group -->
</form>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true"> 靓号</span>
</div>
{# <div class="panel-body">#}
{# Panel content#}
{# </div>#}
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>ID</th>
<th>电话号</th>
<th>价格</th>
<th>等级</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in data_list %}
<tr>
<td>{
{ obj.id }}</td>
<td>{
{ obj.mobile }}</td>
<td>{
{ obj.price }}</td>
<td>{
{ obj.get_level_display }}</td>
<td>{
{ obj.get_status_display }}</td>
<td>
<a href="/num/{
{ obj.id }}/edit/" class="btn btn-primary btn-xs">编辑</a>
<a href="/num/{
{ obj.id }}/delete" class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
4.分页
基本逻辑
queryset = PrettyNum.objects.filter(id=1)[0:10]
# 第一页
queryset = PrettyNum.objects.all()[0:10]
# 第二页
queryset = PrettyNum.objects.all()[10:20]
# 第三页
queryset = PrettyNum.objects.all()[20:30]
# 那么分页可以这样写
page_size = 10
page = int(request.GET.get('page'))
start = (page - 1) * page_size
end = page * page_size
queryset = PrettyNum.objects.all()[start:end]
views.py
def num_list(request):
""" 靓号列表 """
# for i in range(300):
# PrettyNum.objects.create(mobile='18188888818', price=10, level=1, status=1)
page_size = 10
page = int(request.GET.get('page', 1))
start = (page - 1) * page_size
end = page * page_size
total_count = PrettyNum.objects.all().count()
total_page = math.ceil(total_count / page_size)
# 页码,显示当前页的前5页和后5页
"""
<li><a href="/num/list/?page=1">1</a></li>
<li><a href="/num/list/?page=2">2</a></li>
<li><a href="/num/list/?page=3">3</a></li>
<li><a href="/num/list/?page=4">4</a></li>
<li><a href="/num/list/?page=5">5</a></li>
"""
plus = 5
if total_page <= 2 * plus + 1:
# 总页面太少
start_page = 1
end_page = total_page
else:
# 总页面很多
# 但是当前page<plus时
if page <= plus:
start_page = 1
end_page = 2 * plus + 1
# 当前page+plus超过总页面时
elif (page + plus) > total_page:
start_page = total_page - 2 * plus
end_page = total_page
else:
start_page = page - plus
end_page = page + plus
page_str_list = []
# 上一页
if page > 1:
prev = '<li><a href="?page={}">previous</a></li>'.format(page - 1)
else:
prev = '<li><a href="?page={}">previous</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:
nex = '<li><a href="?page={}">next</a></li>'.format(page + 1)
else:
nex = '<li><a href="?page={}">next</a></li>'.format(total_page)
page_str_list.append(nex)
page_string = mark_safe("".join(page_str_list))
data_dict = {}
search_data = request.GET.get("q", "")
if search_data:
data_dict["mobile__contains"] = search_data
# 去数据库中获取所有的靓号列表(降序排列)
queryset = PrettyNum.objects.filter(**data_dict).order_by("-level")[start:end]
return render(request, 'num_list.html',
{"data_list": queryset, "search_data": search_data, 'page_string': page_string})
num_list.html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div style="margin-bottom: 10px" class="clearfix">
<a class="btn btn-success" href="/num/add/">
<span class="glyphicon glyphicon-edit" 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><!-- /input-group -->
</form>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true"> 靓号</span>
</div>
{# <div class="panel-body">#}
{# Panel content#}
{# </div>#}
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>ID</th>
<th>电话号</th>
<th>价格</th>
<th>等级</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in data_list %}
<tr>
<td>{
{ obj.id }}</td>
<td>{
{ obj.mobile }}</td>
<td>{
{ obj.price }}</td>
<td>{
{ obj.get_level_display }}</td>
<td>{
{ obj.get_status_display }}</td>
<td>
<a href="/num/{
{ obj.id }}/edit/" class="btn btn-primary btn-xs">编辑</a>
<a href="/num/{
{ obj.id }}/delete" class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="clearfix">
<ul class="pagination" style="float:left;">
{
{ page_string }}
<li>
<form method="get" style="float:left;">
<div class="input-group" style="width: 150px">
<input type="text" name='page' class="form-control" placeholder="页码">
<span class="input-group-btn">
<button class="btn btn-default" type="submit">跳转</button>
</span>
</div><!-- /input-group -->
</form>
</li>
</ul>
</div>
</div>
{% endblock %}
分页组件的分装
Pagination.py
"""
自定义的分页组件,以后如果想要使用这个分页组件,你需要做如下几件事:
在视图函数文件views.py中:
def num_list(request):
# 1.根据自己的情况去筛选自己的数据
queryset = PrettyNum.objects.all()
# 2.实例化分页对象
page_object = Pagination(request, queryset)
context = {
"data_list": page_object.page_queryset, # 分完页的数据
'page_string': page_object.html(), # 生成的页码
}
return render(request, 'num_list.html', context)
在html文件中:
{% for obj in data_list %}
{
{ obj.xx }}
{% endfor %}
<ul class="pagination" style="float:left;">
{
{ page_string }}
</ul>
"""
import math
from django.utils.safestring import mark_safe
class Pagination(object):
def __init__(self, request, queryset, page_param='page', page_size=10, plus=5):
"""
:param request: 请求对象
:param queryset: 符合对象的数据(根据这个数据进行分页处理)
:param page_param: 在url中传递获取分页的参数,例如/num/list/?page=12
:param page_size: 每页显示多少数据
: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")
if page.isdecimal():
page = int(page)
else:
page = 1
# print(page)
self.page = page
self.page_size = page_size
self.plus = plus
self.start = (self.page - 1) * self.page_size
self.end = self.page * self.page_size
self.page_queryset = queryset[self.start:self.end]
total_count = queryset.count()
# 总页码
self.total_page = math.ceil(total_count / self.page_size)
def html(self):
# 页码,显示当前页的前5页和后5页
if self.total_page <= 2 * self.plus + 1:
# 总页面太少
start_page = 1
end_page = self.total_page
else:
# 总页面很多
# 但是当前page<plus时
if self.page <= self.plus:
start_page = 1
end_page = 2 * self.plus + 1
# 当前page+plus超过总页面时
elif (self.page + self.plus) > self.total_page:
start_page = self.total_page - 2 * self.plus
end_page = self.total_page
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:
self.query_dict.setlist(self.page_param, [self.page + 1])
nex = '<li><a href="?{}">next</a></li>'.format(self.query_dict.urlencode())
else:
self.query_dict.setlist(self.page_param, [self.total_page])
nex = '<li><a href="?{}">next</a></li>'.format(self.query_dict.urlencode())
page_str_list.append(nex)
# 尾页
self.query_dict.setlist(self.page_param, [self.total_page])
page_str_list.append('<li><a href="?{}">尾页</a></li>'.format(self.query_dict.urlencode()))
search_string = """
<li>
<form method="get" style="float:left;">
<div class="input-group" style="width: 150px">
<input type="text" name='page' class="form-control" placeholder="页码">
<span class="input-group-btn">
<button class="btn btn-default" type="submit">跳转</button>
</span>
</div><!-- /input-group -->
</form>
</li>
"""
page_str_list.append(search_string)
page_string = mark_safe("".join(page_str_list))
return page_string
views.py
def num_list(request):
""" 靓号列表 """
data_dict = {}
search_data = request.GET.get("q", "")
if search_data:
data_dict["mobile__contains"] = search_data
# 去数据库中获取所有的靓号列表(降序排列)
queryset = PrettyNum.objects.filter(**data_dict).order_by("-level")
page_object = Pagination(request, queryset)
context = {
"search_data": search_data,
"data_list": page_object.page_queryset, # 分完页的数据
'page_string': page_object.html(), # 生成的页码
}
return render(request, 'num_list.html', context)
num_list.html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div style="margin-bottom: 10px" class="clearfix">
<a class="btn btn-success" href="/num/add/">
<span class="glyphicon glyphicon-edit" 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><!-- /input-group -->
</form>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true"> 靓号</span>
</div>
{# <div class="panel-body">#}
{# Panel content#}
{# </div>#}
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>ID</th>
<th>电话号</th>
<th>价格</th>
<th>等级</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in data_list %}
<tr>
<td>{
{ obj.id }}</td>
<td>{
{ obj.mobile }}</td>
<td>{
{ obj.price }}</td>
<td>{
{ obj.get_level_display }}</td>
<td>{
{ obj.get_status_display }}</td>
<td>
<a href="/num/{
{ obj.id }}/edit/" class="btn btn-primary btn-xs">编辑</a>
<a href="/num/{
{ obj.id }}/delete" class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="clearfix">
<ul class="pagination" style="float:left;">
{
{ page_string }}
</ul>
</div>
</div>
{% endblock %}
5.modelform中的时间插件
在layout.html中在如下位置添加两行
{% block css %}{% endblock %}
{% block js %}{% endblock %}
在user_model_form_add.html中添加如下内容
{% block css %}
<link rel="stylesheet" href="{% static 'plugins/bootstrap-datetimepicker-master/css/bootstrap-datetimepicker.min.css' %}">
{% endblock %}
{% block js %}
<script src="{% static 'plugins/bootstrap-datetimepicker-master/js/bootstrap-datetimepicker.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-datetimepicker-master/js/locales/bootstrap-datetimepicker.zh-CN.js' %}"></script>
<script>
$(function(){
$('#id_create_time').datetimepicker({
format:'yyyy-mm-dd',
startDate: '0',
language: 'zh-CN',
autoclose: true,
});
})
</script>
{% endblock %}
就可以实现ModelForm的时间选择插件了。
6.modelForm和Bootstrap
写一个BootstrapModelForm类,让其他的ModelForm继承
class BootstrapModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有的插件,给每个字段的插件设置
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}
7.优化
在app01目录下创建views文件夹,文件夹内分别创建depart.py,user.py,prettynum.py,将views.py里的内容根据功能复制到相应的文件中,最后删除views.py文件,然后修改urls.py文件里的路径。