分页器
批量操作数据
1.浏览器访问一个django路由,创建100条数据并展示到前端页面
2.当使用create创建大量数据时可能会造成数据库崩溃
批量数据创建>>>:bulk_create()
批量数据修改>>>:bulk_update()
3.实例
def index(request):
book_list = []
for i in range(100):
book_obj = models.Book(title=f'第{i}本书')
book_list.append(book_obj)
models.Book.objects.bulk_create(book_list) # 批量创建数据
book_query = models.Book.objects.all()
return render(request, 'booklist.html', locals())
4.html
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
{% for obj in book_query %}
<p class="text-center">{{ obj.title }}</p>
{% endfor %}
</div>
</div>
</div>
批量数据展示推导
1.当展示的数据量较大时,页面展示应该考虑分页
2.使用QuerySet切片操作
3.复制一个分页样式添加到html文件中
4.根据总数据和每页页数展示数据得出的总页码
all_page_num, more = divmod(all_count, per_page_num)
5.前端模板不支持range,但是后端支持,所以我们可以在后端创建好html标签然后传递给前端html页面使用,这样就可以渲染出所有的页码标签
html_page += '<li><a href="?page=%s">%s</a></li>' % (i, i)
6.页码推荐使用奇数位(对称美),利用当前页前后固定位数来限制展示的页码标签个数,在用判断限制首尾页码展示范围
7.实例
def index(request):
# 获取所有数据
book_data = models.Book.objects.all()
# 计算数据条数
all_count = book_data.count()
# 定义每页展示的数据条数
per_page_num = 10
# 获取每页10条数据需要的页数
all_page_num, more = divmod(all_count, per_page_num)
if more:
all_page_num += 1
# 获取用户指定的page,如果没有则默认展示第一页
current_page = request.GET.get('page', 1)
# 用户输入字符串则默认展示第一页
try:
current_page = int(current_page)
except ValueError:
current_page = 1
# 后端提前生成页码标签
html_page = ''
xxx = current_page
# 如果用户访问的页面小于6,则只渲染到6
if current_page < 6:
xxx = 6
# 如果用户访问的页面大于最大页数,则只渲染到最大页数-5
if current_page > (all_page_num - 5):
xxx = (all_page_num - 5)
# 以用户所选择的页面为中间也,左右各展示五个
for i in range(xxx - 5, xxx + 6):
if current_page == i:
# 如果当前渲染的标签页与用户服务的页面一致,就加class="active"
html_page += '<li><a class="active"href="?page=%s">%s</a></li>' % (i, i)
else:
# 如果当前渲染的标签页与用户服务的页面不一致,就不加
html_page += '<li><a href="?page=%s">%s</a></li>' % (i, i)
# 定义切片起始位置
start_num = (current_page - 1) * per_page_num
# 定义切片终止位置
end_num = current_page * per_page_num
# 分页处理
book_query = book_data[start_num:end_num]
return render(request, 'booklist.html', locals())
'上述只是分页组件的推导流程,实际中无需编写'
自定义分页器
1.我们可以直接导入写好的分页器
from APP01.utils import mypage
# 获取所有数据
book_query = models.Book.objects.all()
# 定义分页
page_obj = mypage.Pagination(current_page=request.GET.get('page'),
all_count=book_query.count())
page_query = book_query[page_obj.start:page_obj.end]
return render(request, 'booklist.html', locals())
2.分页器
class Pagination(object):
def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):
"""
封装分页相关数据
:param current_page: 当前页
:param all_count: 数据库中的数据总条数
:param per_page_num: 每页显示的数据条数
:param pager_count: 最多显示的页码个数
"""
try:
current_page = int(current_page)
except Exception as e:
current_page = 1
if current_page < 1:
current_page = 1
self.current_page = current_page
self.all_count = all_count
self.per_page_num = per_page_num
# 总页码
all_pager, tmp = divmod(all_count, per_page_num)
if tmp:
all_pager += 1
self.all_pager = all_pager
self.pager_count = pager_count
self.pager_count_half = int((pager_count - 1) / 2)
@property
def start(self):
return (self.current_page - 1) * self.per_page_num
@property
def end(self):
return self.current_page * self.per_page_num
def page_html(self):
# 如果总页码 < 11个:
if self.all_pager <= self.pager_count:
pager_start = 1
pager_end = self.all_pager + 1
# 总页码 > 11
else:
# 当前页如果<=页面上最多显示11/2个页码
if self.current_page <= self.pager_count_half:
pager_start = 1
pager_end = self.pager_count + 1
# 当前页大于5
else:
# 页码翻到最后
if (self.current_page + self.pager_count_half) > self.all_pager:
pager_end = self.all_pager + 1
pager_start = self.all_pager - self.pager_count + 1
else:
pager_start = self.current_page - self.pager_count_half
pager_end = self.current_page + self.pager_count_half + 1
page_html_list = []
# 添加前面的nav和ul标签
page_html_list.append('''
<nav aria-label='Page navigation>'
<ul class='pagination'>
''')
first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
page_html_list.append(first_page)
if self.current_page <= 1:
prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
else:
prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)
page_html_list.append(prev_page)
for i in range(pager_start, pager_end):
if i == self.current_page:
temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
else:
temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
page_html_list.append(temp)
if self.current_page >= self.all_pager:
next_page = '<li class="disabled"><a href="#">下一页</a></li>'
else:
next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
page_html_list.append(next_page)
last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
page_html_list.append(last_page)
# 尾部添加标签
page_html_list.append('''
</nav>
</ul>
''')
return ''.join(page_html_list)
1.用form表单编写用户登录功能并且校验数据返回提示信息
def form(request):
data_dict = {'username': '', 'password': ''}
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username == 'barry':
data_dict['username'] = 'barry不可以哦'
if password == '123':
data_dict['password'] = '太短啦'
return render(request, 'abform.html', locals())
2.html
<form action="" method="post">
<p>username:
<input type="text" name="username">
<span style="color: red">{{ data_dict.username }}</span>
</p>
<p>password:
<input type="text" name="password">
<span style="color: red">{{ data_dict.password }}</span>
</p>
<input type="submit">
</form>
1.数据校验
支持提前设置各种校验规则,之后自动校验
2.渲染页面
支持直接渲染获取用户数据的各种标签
3.展示信息
支持针对不同的校验失败展示不同的提示
4.form表单创建
class User(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
email = models.EmailField()
5.form类型创建
from django import forms
class MyForm(forms.Form):
# 用户名最长八个字符,最短三个字符
name = forms.CharField(max_length=8, min_length=3)
# 年龄最小0岁,最大120岁
age = forms.IntegerField(max_value=120, min_value=0)
# 邮箱必须符合格式,至少有个@符
email = forms.EmailField()
1.传递待校验的数据
form_obj = views.MyForm({'name':'barry','age':18,'email':123})
2.判断所有的数据是否符合校验
form_obj.is_valid()
3.获取符合校验规则的数据
orm_obj.cleaned_data # {'name': 'barry', 'age': 18}
4.查阅不符合校验规则的数据及错误原因
form_obj.errors # {'email': ['Enter a valid email address.']}
'''
from类中编写的字段默认是必填的,少传了字段就无法通过校验
校验传多了不存在字段的数据,不会参与其他功能
'''
1.后端要获取我们前面写的MyForm类的对象
def func(request):
form_obj = MyForm()
return render(request, 'abform.html', locals())
2.方式1(封装程度高,扩展性差)
{{ form_obj.as_p }} # 将字段一行行展示p标签展示
{{ form_obj.as_table }} # 将字段label、input标签展示
{{ form_obj.as_ul }} # 将字段渲染成li标签展示
3.方式2(封装程度低 扩展性好,编写困难)
{{ form_obj.name.lable }} # 展示字段名字
{{ form_obj.name }} # 展示字段名的input框
4.方式3(推荐使用)
{% for form in form_obj %}
<p>{{ form.label }}{{ form }}</p>
{% endfor %}
'渲染的标签都是类中存在的,类中以外的所有标签都不会自动渲染,需要自己编写'
1.在后端进行数据校验
def func(request):
form_obj = MyForm()
if request.method == 'POST':
# 将用户上传的全部数据校验
form_obj = MyForm(request.POST)
# 判断数据是否通过校验
if form_obj.is_valid():
# 获取全部数据
print(form_obj.cleaned_data)
else:
# 返回错误信息
print(form_obj.errors)
return render(request, 'abform.html', locals())
2.html
<form action="" method="post" novalidate> # 让前端不做校验
{% for form in form_obj %}
<p>{{ form.label }}{{ form }}
<span style="color: red;">{{ form.errors.0 }}</span> # 获取错误信息的文本
</p>
{% endfor %}
<input type="submit" value="提交">
.修改django默认语言
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'zh-hans'
from django.conf import global_settings # 字符地址
字段参数 |
功能 |
max_length |
最大字数 |
min_length |
最小字数 |
max_value |
最大值 |
min_value |
最小值 |
label |
字段注释 |
error_messages |
错误提示 |
required |
是否为空 |
widget |
标签类型、标签属性 |
initial |
默认值 |
validators |
正则效验 |
钩子函数
1.局部钩子
校验单个字段
def clean_name(self):
# 获取用户名
name = self.cleaned_data.get('name')
# 用用户名从数据库获取用户数据
res = models.User.objects.filter(name=name)
if res:
# 若用户名已存在
return self.add_error('name', '用户名已存在')
# 若是该用户名不存在
return name
2.全局钩子
效验多个字段
def clean(self):
# 获取想要的字段数据
pwd = self.cleaned_data.get('pwd')
confirm_pwd = self.cleaned_data.get('confirm_pwd')
if pwd == confirm_pwd:
# 若用户输入的两次密码不一致
return self.add_error('confirm_pwd', '两次密码不一致')
# 若用户输入的密码一致则返回数据
return self.cleaned_data
1.ModelForm是将Model和Form进行绑定,Form可以自动生成表单的作用,但是每一个forms字段需要自己手动填写,而Model就是数据库包含了所有的数据字段,所以ModelForm有着Form的所有功能也能将Model字段自动转成forms字段
2.实例
from django import forms
class MyModeForm(forms.ModelForm):
class Meta:
# 要对那张表进行校验
model = models.User
# 对这张表的所有字段校验
fields = '__all__'
def clean_name(self):
# 获取用户名
name = self.cleaned_data.get('name')
# 用用户名从数据库获取用户字段
res = models.User.objects.filter(name=name).first()
if res:
# 若用户名已存在
return self.add_error('name', '用户名已存在')
# 若是该用户名不存在则数据返回
return name
3.常用参数
model = models.Book>>>与那个类做对应
fields = '__all__'>>>表示列出所有的字段
exclude = None>>>排除调不参与的字段
labels = None>>>给标签加提示信息
help_texts = None>>>帮助提示信息
widgets = None>>>给标签加属性
error_messages = None>>>自己定义错误信息