1. Edit user (based on modelform)
Click Edit to jump to the editing interface (carry the id of the edited row)
Edit page (default data, get and set page according to id)
Submit: error message, data verification, update in database
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. Delete user
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. Prestigious number management
3.1 Create table structure
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)
create some data
mysql -u root -p
use db2;
insert into app01_prettynum(mobile, price, level, status) values('11111111111', 19, 1, 1);
3.2 List of pretty numbers
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 Create a new account
List click [add beautiful number] to jump to /num/add/
Create the NumModel class
def num_add function:
GET: instantiate the object of the class, pass the object into html through render, and use the template to display all the fields in a loop.
POST: click submit, data verification, save to database, jump to /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 Editing a good number
Add num_list.html: href="/num/{ { obj.id }}/edit/"
urls.py added: path('num//edit/', views.num_edit),
Create NumEditModelForm class (not allowed to edit mobile phone number)
num_edit function
GET: get the currently edited object according to id
POST: Submit changes
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 %}
If at this time, it is allowed to modify the phone number (that is, delete the sentence mobile = forms.CharField(disabled=True, label='mobile phone number')), how to verify that the mobile phone number and other data in the database are not duplicated at this time? Or write a function clean_mobile() in the class NumEditModelForm
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 Delete the good number
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 Search phone number
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. Pagination
basic logic
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 %}
Packing of pagination components
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. Time plug-in in modelform
Add two lines in layout.html in the following position
{% block css %}{% endblock %}
{% block js %}{% endblock %}
Add the following content in 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 %}
The time selection plug-in of ModelForm can be realized.
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文件里的路径。