day68——使用自定义分页器、Forms组件功能与应用
作者:互联网
自定义分页器的拷贝与使用
当我们需要用到非django内置的第三方功能或组件的时候,由于拷过来的东西不能瞎放,我们一般会创建一个名为utils的文件夹来存放。该文件夹可以在django根目录下创建;在分组开发每个应用需要不同组件的时候,也可以在每个应用下分别创建utils的文件夹,具体根据实际情况来定。
注意:
上述自定义的分页器是基于bootstrap样式来了,使用时页面需要导入bootstrap。
后端
代码很简单,将分页器代码拷贝到utils文件夹下需要使用时导入Pagination
即可;给类传值生成对象,利用分区器对象的start和end属性对总数据进行切片获取当前页需要展示的数据,然后将数据传入html页面展示。
book_queryset = models.Book.objects.all()
current_page = request.GET.get('page',1)
all_count = book_queryset.count()
# 1 传值生成对象
page_obj = Pagination(current_page=current_page,all_count=all_count)
# 2 直接对总数据进行切片操作
page_queryset = book_queryset[page_obj.start:page_obj.end]
# 3 将page_queryset传递到页面 替换之前的book_queryset
前端
自定义分页器代码中已经封装好了bootstrap分页器的样式,分页器用模版语法直接.page_html
使用即可,无需自己渲染分页器,需加上|safe
进行转义,当然也可以在后端完成转义。
# 前端
{% for book_obj in page_queryset %}
<p>{{ book_obj.title }}</p>
<nav aria-label="Page navigation">
</nav>
{% endfor %}
{#利用自定义分页器直接显示分页器样式#}
{{ page_obj.page_html|safe }}
Forms组件
我们先写一个简单的注册功能来一步步引出Forms组件。
注册功能需求:
前端页面获取用户名和密码,利用form表单提交数据,后端接收到数据进行数据的校验,看是否满足用户名不能含有字符'666'以及密码不能小于三位的条件,如果不满足条件,则在前端页面展示错误信息。
后端:
def id_check(request):
msg_dict = {'username': '', 'password': ''} # 定义一个值是空字符串的字典
if request.method == 'POST':
username = request.POST.get('username') # 获取用户的输入的信息
password = request.POST.get('password')
if '666' in username: # 对数据进行校验,有错则给字典对应的字段添加错误信息
msg_dict['username'] = '不能做一条只会喊6的咸鱼'
if len(password) < 3:
msg_dict['password'] = '密码还是长点安全'
return render(request, 'id_check.html', locals())
"""无论是get请求还是post请求都能给页面返回错误信息字典,post请求来的时候字段可能有值。"""
前端:
<form action="" method="post">
<p>用户名:
<input type="text" name="username">
{#span便签的大小取决于文本,只有在字典有错误信息时才能取到值进行展示,否则span标签隐藏不展示#}
<span style="color: red">{{ msg_dict.username }}</span></p>
<p>密码:
<input type="text" name="password">
<span style="color: red">{{ msg_dict.password }}</span></p>
<p><input type="submit"></p>
</form>
实现该注册功能我们的总共干了三件事:
- 手动书写前端获取用户数据的html代码——>渲染html代码
- 后端对用户数据进行校验——>校验数据
- 对不符合要求的数据进行前端提示——>展示提示信息
渲染html、代码校验数据、展示提示信息Forms组件都可以实现,无需我们书写繁杂的代码。
后端校验的重要性
数据的校验可分为前端数据校验和后端的数据校验;前端的数据校验可有可无,因为可以在浏览器内进行修改,而后端校验才是必须要有了,保护服务端数据的安全。
Forms组件基本使用
需要先充django中导入forms模块,书写的时候跟写模型表类似。
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()
校验数据:
之前我们学习了测试脚本的创建,但其实pycharm已经准备好一个测试环境python console
,在charm页面的正下方打开就可以测试代码,在创建数据时,可以帮我们每个字段是否合法。
from app01 import views
# 1 将带校验的数据组织成字典的形式传入即可
form_obj = views.MyForm({'username':'jason',
'password':'123',
'email':'123'})
# 2 判断数据是否合法,注意该方法只有在所有的数据全部合法的情况下才会返回True
form_obj.is_valid()
# False
# 3 查看所有校验通过的数据
form_obj.cleaned_data
# {'username': 'jason', 'password': '123'}
# 4 查看所有不符合校验规则以及不符合的原因
form_obj.errors
"""{
'email': ['Enter a valid email address.']
}"""
# 5 校验数据只校验类中出现的字段 多传不影响 多传的字段直接忽略
form_obj = views.MyForm({'username':'jason',
'password':'123',
'email':'123@qq.com',
'hobby':'study'})
form_obj.is_valid()
# True
res4.errors
# {}
# 6 校验数据 默认情况下 类里面所有的字段都必须传值
form_obj = views.MyForms({'username':'jason',
'password':'111'})
print(res4.is_valid())
# True
form_obj.errors
# {'email': ['This field is required.']}
"""
也就意味着校验数据的时候 默认情况下数据可以多传但是绝不可能少传
"""
渲染标签
form组件会自动渲染获取用户输入的标签(input radio checkbox select textarea ...)
但是它不会渲染提交标签,需要我们自己书写代码渲染。
后端:
def randering_label(request):
form_obj = MyForms() # 先生成空对象
return render(request,'ren_label.html') # 直接将空对象传给页面
前端渲染:
-
方式一:
<body> {{ form_obj.as_p }} <!--每个标签单独占一行--> {{ form_obj.as_ul }} <!--每个标签单独占一行,竖向无序排列--> {{ form_obj.as_table }} <!--标签横向按表格的形式排列--> </body>
第一种方式书写的代码最少,最为方便,但是封装程度太高,不利于后期的扩展,一般只在本地测试使用。
-
方式二:
逐个标签进行渲染,扩展性强,但是需要书写的代码太多。如果标签过多逐个书写太麻烦,一般情况不使用这种渲染方式。
<body> {{ form_obj.username.label }}:{{ form_obj.username }} {{ form_obj.password.label }};{{ form_obj.password }} </body>
label属性默认展示的是类中定义的字段首字母大写的形式,还可以自己修改,在对应字段对象指定label参数即可
...max_length=8,label='用户名')
-
方式三:
利用循环的方式减少代码的书写,并且有一定的扩展性,推荐使用
<body> {% for form in form_obj %} <p>{{ form.label }}:{{ form }}</p> <!--用p标签包裹将每个标签单行展示--> {% endfor %} </body>
展示提示信息
取消浏览器校验数据novalidate
我们给页面传一个空的form对象,后端不进行数据的校验时;在输入框中输入不合法的数据提交数据后,输入框向下弹出样式很好看的提示信息,这其实是浏览器帮我做的校验,但这种校验弱不禁风,浏览器内修改前端代码就会失效。
def ren_label(request):
form_obj = MyForms()
return render(request, 'ren_label.html', locals())
浏览器对该字段的校验代码:
<input type="text" name="username" maxlength="6" minlength="3" required="" id="id_username">
我们右键检查在浏览器内将该校验条件修改:
<input type="text" name="username" maxlength="6" minlength="2" required="" id="id_username">
再次提交用户名'66'校验就失效了
这也验证了前端校验的不可靠性和后端校验的重要性
可在前端form便签内设置浏览器不进行校验
<form action="" method="post" novalidate>
form组件展示提示信息
后端:
def check_data(request):
# 1 先产生一个空的form对象
form_obj = MyForm()
# 2 定义一个空字字典,如果数据通过校验,给字典添加“注册成功”提示信息
back_msg = {'success': ''}
if request.method == 'POST':
# 3 可将request.POST看是一个字典当参数传入
form_obj = MyForm(request.POST)
# 4.校验数据
if form_obj.is_valid():
back_msg['success'] = '注册成功'
return render(request, 'ren_label.html', locals())
"""无论是GET请求还是POST请求都能返回一个form对象给页面,
POST请求来的时候对象可能不为空"""
注意:为了保证html页面不管什么情况下都能有一个form对象来渲染标签,get请求和post传给html页面对象变量名必须一样。
前端:
<body>
<form action="" method="post" novalidate>
<h1 class="text-center">注册页面</h1>
{% for form in form_obj %}
<p>{{ form.label }}:{{ form }}<span style="color:red">{{ form.errors.0 }}</span></p>
{% endfor %}
<input type="submit" class="btn-success btn-lg">
<span style="font-size: large;color:green" class="span">{{ back_msg.success }}</span>
</form>
<script>function clean_span() {
$('.span') .remove()
}
setInterval(clean_span, 2000)
</script>
</body>
form.errors.0
:错误信息可能为多个所以是一个列表,在展示的时候会被渲染成无序列表的形式,按索引取值取消这种渲染。
数据校验不通过展示提示信息:
通过校验提示注册成功:
forms组件会保存你上次的数据,让你基于之前的结果进行修改,更加的人性化。
自定义错误信息:
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':"用户名不能为空"
}
# email字段必须符合邮箱格式 xxx@xx.com
email = forms.EmailField(label='邮箱',
error_messages={
'invalid':'邮箱格式不正确',
'required': "邮箱不能为空"
}
)
钩子函数(HOOK):
在特定的节点自动触发完成响应操作,钩子函数相当于forms组件的第二道数据校验关卡,能够支持我们自定义校验规则
forms组件两类钩子函数:
-
局部钩子函数
当你需要给单个字段增加校验规则的时候可以使用
eg:对用户名进行校验,里面不能含有字符'6';单个字段username的校验用局部钩子函数
-
全局钩子函数
当你需要给多个字段增加校验规则的时候可以使用
eg:核对密码和确认密码是否一致;两个字段校验数据用全局钩子函数
# 钩子函数在类里面书写方法即可
class MyForm(forms.Form):
# 1 局部钩子函数
def clean_username(self):
# 获取到用户名
username = self.cleaned_data.get('username')
if '6' in username:
self.add_error('username', '光喊6是不行滴!')
# 将钩子函数钩去出来数据再放回去
return username
# 2 全部钩子函数
def clean(self):
password = self.cleaned_data.get('password')
conform_password = self.cleaned_data.get('conform_password')
if conform_password != password:
self.add_error('conform_password', '密码不一致')
# 全局钩子函数将所有数据再放回去
return self.cleaned_data
对数据内容进行二次校验:
forms组件其他参数及补充知识点:
-
label(汉字/英文)——>字段名(英文则首字母大写)
-
error_messages(
{'字段校验条件':'错误信息',}
)——>自定义报错信息 -
required(True/False)——>控制字段是否必填
-
widget——>为标签修改样式
widget=forms.widgets.PasswordInput(attrs={'class':'form-control c1 c2'}) # 具有bootstrap样式的密文输入框 widget=forms.widgets.Select() # 下拉选择框
-
第一道关卡里面还支持正则校验:
validators=[ RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头') ]
其他类型渲染
# 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()
)
创建字段时forms跟有Choice
表示该字段为可选类型,MultipleChoice
表示多选,widgets后面点什么就是什么类型的输入标签,...select
:表示单选,...SelectMultiple
:表示多选;标签类型的单选和多选必须跟字段匹配。
标签:username,forms,obj,自定义,form,校验,Forms,day68,password 来源: https://www.cnblogs.com/zhangtieshan/p/13054318.html