day68 form组件
一、自定义分页器的拷贝和使用
在django中一些第三方的组件我们可以单独建一个文件夹utils去存放,分页器就是这样的组件
utils>fenyeqi.py
class Pagination(object):
def __init__(self, current_page, all_count, per_page_num=15, 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)
分页器代码不需要完全会写,只要知道这个类如何使用以及几个关键性参数就行了
app01>views.py
from app01 import models
# 导入分页器模块
from utils import fenyeqi
def fenye(request):
# 获取需要分页的所有数据对象
all_queryset = models.Author.objects.all()
# 1 统计数据对象个数
all_count =all_queryset.count()
# 2 实例化分页器对象
# 3 同时获取前端传来的get请求中page页数
# 4 这里还有一个参数per_page_num,虽然是默认参数,但是我们通常要自己制定每页展示的数据,要知道是实例化的时候这个参数的修改
fenye_obj = fenyeqi.Pagination(current_page=request.GET.get('page',1) ,all_count=all_count)
# 5 获取每页展示的数据对象
page_queryset = all_queryset[fenye_obj.start:fenye_obj.end]
return render(request,'fenyeqi.html',locals())
template>fenyeqi.html
<body>
# 通过for循环展示要显示的内容
{% for obj in page_queryset %}
<p>{{ obj.name }}</p>
{% endfor %}
# 展示分页器,记得加safe
{{ fenye_obj.page_html |safe}}
</body>
二、Forms组件
1 前戏
用我们现在所学的知识完成,判断用户名密码是否符合规范:
用户名不能含有金梅
密码不能少于三位
后端
def ab_form(request):
back_dic = {'username':'','password':''}
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if '金梅' in username:
back_dic['username'] = '不符合社会主义核心价值观'
if len(password) < 3:
back_dic['password'] = '不能太短 不好!'
return render(request,'ab_form.html',locals())
# get请求来的时候,返回的是一个没有报错信息的字典,post请求来的时候对数据进行判断返回的是一个可能携带报错信息的字典
前端
// 通过一个span标签展示报错信息
<form action="" method="post">
<p>username:
<input type="text" name="username">
<span style="color: red">{{ back_dic.username }}</span>
</p>
<p>password:
<input type="text" name="password">
<span style="color: red">{{ back_dic.password }}</span>
</p>
<input type="submit" class="btn btn-info">
</form>
2 form组件的基本功能
- 渲染html代码
- 效验数据
- 展示提示信息
提示:前端的数据校验可有可无,后端必须要有数据校验
因为在爬虫程序可以绕过前端直接向服务端发起请求
3 基本使用
from django import forms
class MyForm(forms.Form):
# username字符串类型最小3位最大8位
username = forms.CharField(min_length=3,max_length=8)
# password字符串类型最小3位最大8位
password = forms.CharField(min_length=3,max_length=8)
# email字段必须符合邮箱格式 xxx@xx.com
email = forms.EmailField()
4 基本方法
# 在pycharm中又一个自带的测试环境:python console
# 1 实例化form对象,这里的数据传多了不报错,但是不能少了类中有的,因为默认每个字段都是非空的
form_obj = views.MyForm({'username':'hz','password':'1111','email':'1@qq.com'})
# 2 判断数据是否合法,只有在全部合法的情况下才会返回True
form_obj.is_valid()
False
# 3 查看所有通过校验的数据
form_obj.cleaned_data
{'username':'hz','password':'1111'}
# 4 查看所有不符合校验规则及其原因
form_obj.errors
{'usrename': ['Ensure this value has at least 3 characters (it has 2).']}
5 渲染标签
forms组件只会自动帮你渲染获取用户输入的标签(input select radio checkbox),不会帮我们渲染提交按钮
后端
def index(request):
# 1 先产生一个空对象
form_obj = MyForm()
# 2 直接将该空对象传递给html页面
return render(request,'index.html',locals())
前端
# 前端利用空对象做操作
<p>第一种渲染方式:代码书写极少,封装程度太高 不便于后续的扩展 一般情况下只在本地测试使用</p>
{{ form_obj.as_p }}
{{ form_obj.as_ul }}
{{ form_obj.as_table }}
<p>第二种渲染方式:可扩展性很强 但是需要书写的代码太多 一般情况下不用</p>
<p>{{ form_obj.username.label }}:{{ form_obj.username }}</p>
<p>{{ form_obj.password.label }}:{{ form_obj.password }}</p>
<p>{{ form_obj.email.label }}:{{ form_obj.email }}</p>
<p>第三种渲染方式(推荐使用):代码书写简单 并且扩展性也高</p>
{% for form in form_obj %}
<p>{{ form.label }}:{{ form }}</p>
{% endfor %}
"""
label属性默认展示的是类中定义的字段首字母大写的形式
也可以自己修改 直接给字段对象加label属性即可
username = forms.CharField(min_length=3,max_length=8,label='用户名')
"""
6 展示提示信息
'''
在我们在前端写需要校验的一些标签的时候,浏览器会自动帮我们以我们的要求校验,且会提示中文的报错信息
虽然这样的提示很智能,但是封装程度很高,不好修改样式
而且浏览器的校验非常的容易绕过可有可无,必须要在后端进行数据校验
如何让浏览器不做校验
<form action="" method="post" novalidate>
'''
后端
'''
1.必备的条件 get请求和post传给html页面对象变量名必须一样
2.forms组件当你的数据不合法的情况下 会保存你上次的数据 让你基于之前的结果进行修改
更加的人性化
'''
def index(request):
# 1 先产生一个空对象
form_obj = MyForm()
if request.method == 'POST':
# 获取用户数据并且校验
"""
1.数据获取繁琐
2.校验数据需要构造成字典的格式传入才行
ps:但是request.POST可以看成就是一个字典
"""
# 3.校验数据
form_obj = MyForm(request.POST)
# 4.判断数据是否合法
if form_obj.is_valid():
# 5.如果合法 操作数据库存储数据
return HttpResponse('OK')
# 5.不合法 有错误
# 2 直接将该空对象传递给html页面
return render(request,'index.html',locals())
前端
{% for form in form_obj %}
<p>
{{ form.label }}:{{ form }}
<span style="color: red">{{ form.errors.0 }}</span>
</p>
{% endfor %}
我们也可以自己定制错误信息,针对的是我们限定的条件和一些自带的条件
# 针对错误的提示信息还可以自己自定制
class MyForm(forms.Form):
# username字符串类型最小3位最大8位
username = forms.CharField(min_length=3,max_length=8,label='用户名',
error_messages={
'min_length':'用户名最少3位',
'max_length':'用户名最大8位',
'required':"用户名不能为空"
}
)
# password字符串类型最小3位最大8位
password = forms.CharField(min_length=3,max_length=8,label='密码',
error_messages={
'min_length': '密码最少3位',
'max_length': '密码最大8位',
'required': "密码不能为空"
}
)
# email字段必须符合邮箱格式 xxx@xx.com
email = forms.EmailField(label='邮箱',
error_messages={
'invalid':'邮箱格式不正确',
'required': "邮箱不能为空"
}
)
7 钩子函数(HOOK)
'''
钩子函数会在特定情况触发,无需调用
钩子函数想到与forms组件的第二道关卡,在最基本的检测通过后,就会经历钩子函数的检测,是我们自定义的检测规则
在forms组件中有两种钩子
1 局部钩子:对单个字段增加校验规则的时候使用
2 全局钩子:对多个字段增加校验规则的时候使用
'''
# 局部钩子
def clean_username(self):
# 获取到用户名
username = self.cleaned_data.get('username')
if '666' in username:
# 提示前端展示错误信息
self.add_error('username','光喊666是不行滴~')
# 将钩子函数钩去出来数据再放回去
return username
# 全局钩子
def clean(self):
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if not confirm_password == password:
self.add_error('confirm_password','两次密码不一致')
# 将钩子函数钩出来数据再放回去
return self.cleaned_data
8 forms组件其他参数及补充
'''
label 字段名,标签前显示
error_messages 自定义报错信息,以字段存放对应每个报错信息
initial 默认值
required 是否可以为空
'''
# 字段的标签样式也可以修改,添加参数widget
# forms.widgets是固定写法,后面自定义
# 不同的样式用空格隔开
widget=forms.widgets.PasswordInput(attrs={'class':'form-control c1 c2'})
其他类型的渲染
# radio
gender = forms.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3,
widget=forms.widgets.RadioSelect()
)
# select
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=3,
widget=forms.widgets.Select()
)
# 多选
hobby1 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
# 单选checkbox
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
# 多选checkbox
hobby2 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)
day68 form组件的更多相关文章
- Django之Form组件
Django之Form组件 本节内容 基本使用 form中字段和插件 自定义验证规则 动态加载数据到form中 1. 基本使用 django中的Form组件有以下几个功能: 生成HTML标签 验证用户 ...
- Python之路【第二十一篇】:Django之Form组件
Django之Form组件 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 小试牛刀 1. ...
- 第十一篇:web之Django之Form组件
Django之Form组件 Django之Form组件 本节内容 基本使用 form中字段和插件 自定义验证规则 动态加载数据到form中 1. 基本使用 django中的Form组件有以下几个功 ...
- 小而美的 React Form 组件
背景 之间在一篇介绍过 Table 组件< React 实现一个漂亮的 Table > 的文章中讲到过,在企业级后台产品中,用的最多且复杂的组件主要包括 Table.Form.Chart, ...
- django框架中的form组件的用法
form组件的使用 先导入: from django.forms import Form from django.forms import fields from django.forms impor ...
- Web框架django[Form]组件
新手上路 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 小试牛刀 1.创建Form类 # 创 ...
- 32.Django form组件
Form组件 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 创建Form类时,主要涉及到 [ ...
- python Django之Form组件
python Django之Form组件 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 小试 ...
- django Form组件 上传文件
上传文件 注意:FORM表单提交文件要有一个参数enctype="multipart/form-data" 普通上传: urls: url(r'^f1/',views.f1), u ...
随机推荐
- 朋友,您可能是MCR的受害者
2018 年五月之后,微软将后续发布的所有 docker image 都推送到了 MCR (Miscrosoft Container Registry),但在中国大陆,它的速度实在是令人发指,本文将介 ...
- <WP8开发学习笔记>动态修改启动时导航的第一个页面(如登录前启动页为LoginPage,登录后变为MainPage)
很多时候我们需要在启动程序的时候根据状态改变初始导航页面,比如程序在启动的时候判断用户是否登录, 如果未登录则跳转到LoginPage.xaml否则跳转到MainPage界面. 这时候就要分析程序的启 ...
- CocosCreator实现微信排行榜
1. 概述 不管是在现实生活还是当今游戏中,各式各样的排名层出不穷.如果我们做好一款游戏,却没有实现排行榜,一定是不完美的.排行榜不仅是玩家了解自己实力的途径,也是游戏运营刺激用户留存的一种途径.在微 ...
- git添加所有新文件
git add -A 提交所有变化 git add -u 提交被修改(modified)和被删除(deleted)文件,不包括新文件(new) git add . 提交新文件(new)和被修改(mod ...
- CVE-2020-0796—远程代码执行漏洞
一.漏洞名称: 微软SMBv3 Client/Server - 远程代码执行漏洞——CVE-2020-0796 二.识别点: 445端口 三.影响范围: Windows 10 Version 1903 ...
- HashSet扩容机制在时间和空间上的浪费,远大于你的想象
一:背景 1. 讲故事 自从这个纯内存项目进了大客户之后,搞得我现在对内存和CPU特别敏感,跑一点数据内存几个G的上下,特别没有安全感,总想用windbg抓几个dump看看到底是哪一块导致的,是我的代 ...
- 0xC0000005: Access Violation -vc++6.0
0xC0000005: Access Violation -vc++6.0 aps001,002,003创建的C:\SMW200DATA\DATA,内容是不一样的,不通用的.读取相关文件就会报错咯. ...
- 解决错误 CS1617 Invalid option '7.1' for /langversion; must be ISO-1, ISO-2, Default or an integer in range 1 to 6.
解决错误 CS1617 Invalid option '7.1' for /langversion; must be ISO-1, ISO-2, Default or an integer in ra ...
- Linux nohup命令详解,终端关闭程序依然可以在执行!
大家好,我是良许. 在工作中,我们很经常跑一个很重要的程序,有时候这个程序需要跑好几个小时,甚至需要几天,这个时候如果我们退出终端,或者网络不好连接中断,那么程序就会被中止.而这个情况肯定不是我们想看 ...
- 【SEED Labs】DNS Rebinding Attack Lab
Lab Overview 实验环境下载:https://seedsecuritylabs.org/Labs_16.04/Networking/DNS_Rebinding/ 在这个实验中模拟的物联网设备 ...