Django form组件 - 神奇的后端直接渲染HTML

news/2025/1/7 21:21:50/

前言

之前在HTML页面中利用form表单向后端提交数据时会写一些获取用户输入的标签并且使用form标签将其包裹起来。并且很多场景下都需要对用户的输入做校验,比如用户输入的长度和格式等,如果用户输入的有误就需要在页面上相应的位置显示相应的错误信息。而django form组件实现了上面所述的功能。

form组件功能

总结起来,django from组件的主要功能有以下三点:

①生成页面可用的HTML标签;

②对用户提交的数据进行校验;

③保留上次输入的内容。

form组件基本使用

form组件的使用和django模型非常类似,现在应用下的views.py中定义好form类,代码如下:

# views.py
from django import forms
class MyForm(forms.Form):'''# username字符串类型最小3位最大8位# password字符串类型最小3位最大8位# email字段必须符合邮箱格式  xxx@xx.com# label属性用来指定字段展示信息'''# username字符串类型,最小3位,最大8位username = forms.CharField(max_length=8,min_length=3, lable='用户名')# password,字符串类型,最小3位,最大8位password = forms.CharField(max_length=8,min_length=3, lable='密码')# email字段必须符合邮箱格式email = forms.EmailField(lable='邮箱')

测试form组件的环境也有两种方式,一种方式同样是通过test.py,另一种方式就是通过pycharm的测试环境Python console,这里采用第二种方式进行测试。

# 1 导入需要测试的文件
from first import views# 2 将需要校验的数据组织成字典的形式传入自定义的form类进行校验
form_obj = views.MyForm({'username':'python',,'emali':'123'})# 3 判断数据是否合法:注意该方法只有在所有的数据全部合法的情况下才会返回True
form_obj.is_valid()  # False# 4 查看所有通过校验的数据
form_obj.cleaned_data  # {'username': 'python', }# 5 查看所有不符合校验规则的字段和不符合原因,错误原因是列表,因为可能错误原因有多个
form_obj.errors  # {'email': ['Enter a valid email address.']}# 6 如果校验数据中出现了类中没有的字段,forms组件只会校验存在的字段,不存在的字段传了直接忽略
form_obj = views.MyForm({'username':'python',,'emali':'123@qq.com','hobby':'read'})
form_obj.is_valid()  # True# 7 默认情况下,类里面所有的字段都必须传值,也就意味着校验数据的时候,默认情况下数据可以多传但是不能少传
form_obj = views.MyForm({'username':'jason',})
form_obj.is_valid()  # False

form组件的校验规则可以总结出以下方法:

给MyForm传值实例化对象,传值方式:将带校验的字段和数据组织成字典的形式
is_valid()		该方法只有在所有的数据全部合法的情况下才会返回True
cleaned_data	查看所有校验通过的数据
errors			查看所有不符合校验规则以及不符合的原因,{key: ['']}
has_error()		判断某一个字段是否不合法,不合法返回True校验数据只校验类中出现的字段,多传不影响,多传的字段直接忽略
校验数据 默认情况下 类里面所有的字段都必须传值,即少传肯定不合法

form组件渲染标签

上面提到form组件可以自动帮忙渲染获取用户输入的标签(input select radio checkbox),但是不能自动渲染提交按钮,那么是如何实现的呢?首先是后端的代码,在views.py中书写视图函数:

# views.py
def index(request):# 先产生一个空对象form_obj = MyForm()if request.method == 'POST':# 获取用户数据进行校验,如果一条一条的获取用户数据太过繁琐,而且校验数据需要字典格式,而request.POST获取到的数据格式就是queryset——dict对象form_obj = MyForm(request.POST)# 如果数据合法应该操作数据库,这里先简写if form_obj.is_valid():return HttpResponse('OK')# 如果是get请求返回直接将空对象传递给html页面return render(request,'register.html',locals())

如果数据不合法需要将错误信息展示到前端,那么如何将错误信息展示到前端呢?因为form校验产生的错误信息就是字典格式,到前端就是自定义对象,所以可以通过前端点点点的方式,下面是前端register.html页面

<body>
<form action="" method="post" novalidate>  <!--novalidate参数阻止浏览器自动校验-->{% for form in form_obj %}<p>{{ form.label }} : {{ form }}<!--span是预留的展示错误信息的标签,form.errors.0的意思是只展示第一条错误提示,否则forms组件会将错误信息展示成无序列表的形式--><span style="color: red">{{ form.errors.0 }}</span></p>{% endfor %}<input type="submit">
</form>
</form>
</body>

错误信息在前端显示都是英文的,能不能改成中文的呢?可以通过参数error_messages来自定制错误信息。

class MyForm(forms.Form):'''error_messages参数需要构造成字典的数据结构,key是校验条件,value是校验失败时的提示信息'''username = forms.CharField(min_length=5,max_length=12,label='用户名',error_messages={'min_length': '用户名不能少于5位','max_length': '用户名不能超多12位','required': '用户名不能为空',})password = forms.CharField(min_length=6, max_length=12, label='密码')re_password = forms.CharField(min_length=6, max_length=12, label='确认密码')email = forms.EmailField(label='邮箱')

HOOK钩子函数

上述form组件的基本使用只是对数据的第一层校验,很多时候对参数还需要一些特殊的校验规则,这时候就可以使用钩子函数,钩子函数在form组件中类似于第二道校验,能够让我们自定义校验规则,校验流程通过第一层校验之后就会来到钩子函数,可以在钩子函数中进一步定制校验规则,钩子函数分为两种分别是局部钩子和全局钩子,钩子函数定义在form类中。

局部钩子

当需要给单个字段增加校验规则的时候就可以使用局部钩子了。比如规定用户名中不能包含hook

# views.py
class MyForm(forms.Form):username = forms.CharField(min_length=5,max_length=12,label='用户名',error_messages={'min_length':'用户名不能少于5位','max_length':'用户名不能超多12位','required':'用户名不能为空',})def clean_username(self):username = self.cleaned_data.get('username')if '666' in username:self.add_error('username', '中包含了hook')return username

定义局部钩子函数可以总结为以下几点:

①局部钩子的函数名为:clean_字段(),字段就是自定义校验规则的字段;

②该方法中在cleaned_data中获取该字段的数据,局部钩子中只能拿到当前字段的数据;

③校验数据失败时,通过add_error方法给字段添加错误信息;

④局部钩子取出的字段数据一定要返回出去。

全局钩子

当需要给多个字段增加校验规则的时候可以使用全局钩子。比如校验两次密码输入是否一致:

# views.py
class MyForm(forms.Form):password = forms.CharField(min_length=6, max_length=12, label='密码')re_password = forms.CharField(min_length=6, max_length=12, label='确认密码')def clean(self):password = self.cleaned_data.get('password')re_password = self.cleaned_data.get('re_password')if password != re_password:self.add_error('re_password', '两次密码输入不一致')return self.cleaned_data

定义全局钩子函数可以总结为以下几点:

①全局钩子可以在cleaned_data内获得任意字段的数据;

②全局钩子取出的cleaned_data一定要返回出去。

form组件参数介绍

首先是常用参数:

min_length			最少几位字符
max_length			最多几位字符
label				字段名
required  			控制字段是否必填(默认required=True)
error_messages  	自定义报错信息,字典的结构
initial  			初始值,input框里面的初始值value

HTML页面上的标签可以修改属性,那么form组件是直接渲染的,如何修改标签的属性呢?就是通过widget参数,通过该参数可以修改标签的属性。

class MyForm(forms.Form):username = forms.CharField(min_length=5,max_length=12,widget=forms.widgets.TextInput(attrs={'class': 'form-control'}))"""
总结:
widget=forms.widgets.TextInput()默认是TextInput(及input[type='text'])
widget=forms.widgets.PasswordInput()密码格式
widget=forms.widgets.EmailInput()邮箱格式attrs提供字段的属性,可以是内置的也可以是自定义的;如有多个class:空格隔开即可。
"""

另外在第一道校验规则中,还支持正则校验,就是通过validators参数进行正则校验:

from django import forms
from django.core.validators import RegexValidatorclass MyForm(forms.Form):phone = forms.CharField(label='手机号',validators=[RegexValidator(r'^[0-9]+$', '请输入数字'),RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],)"""
总结:
validators的值是一个列表,烈面可以更多个正则表校验条件
RegexValidator第一个参数是正则表校验条件,第二个是校验失败是的提示信息"""

form组件其他标签渲染

form组件不止能对input框进行渲染,也支持对radio select checkbox标签进行渲染:

# radio单选
gender = forms.ChoiceField(choices=((1, "男"), (2, "女"), (3, "保密")),label="性别",initial=1,widget=forms.widgets.RadioSelect()
)# checkbox多选
hobby = forms.MultipleChoiceField(choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),label="爱好",initial=[1, 3],widget=forms.widgets.CheckboxSelectMultiple()
)# 下拉单选:即使添加attrs={'multiple': 'multiple'}任然为单选
hobby2 = forms.ChoiceField(choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),label="爱好",initial=3,widget=forms.widgets.Select()
)# 下拉多选
hobby3 = forms.MultipleChoiceField(choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),label="爱好2",initial=[1, 3],widget=forms.widgets.SelectMultiple()
)# 选择checkbox是否选择, initial空表示False, 只要有值就是True默认选中(任何值都可以)
keep = forms.ChoiceField(choices=(('False', 0), ('True', 1)),label="是否记住密码",initial='',widget=forms.widgets.CheckboxInput()
)

在使用choice参数时如果choices展示的数据是动态从数据库中获取的,还需要额外的设置:

class BookAddForm(forms.Form):name = forms.CharField(label='图书名称',error_messages={'required': '图书名称不能为空'},widget=forms.widgets.TextInput())price = forms.DecimalField(label='价格',error_messages={'required': '图书价格不能为空'},widget=forms.widgets.TextInput())publish_date = forms.DateField(label='出版日期',error_messages={'required': '出版日期不能为空'},widget=forms.widgets.DateInput())publish_id = forms.ChoiceField(label='出版社',error_messages={'required':'出版社不能为空'},widget=forms.widgets.Select())author = forms.MultipleChoiceField(label='作者',error_messages={'required':'作者不能为空'},widget=forms.widgets.SelectMultiple())def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)# choices字段的数据动态来自数据库self.fields['publish_id'].choices = models.Publish.objects.values_list('pk', 'name')self.fields['author'].choices = models.Author.objects.values_list('pk', 'name')


http://www.ppmy.cn/news/57556.html

相关文章

小 C 的数学(math)

祝大家劳动节快乐&#xff01;&#xff01;小手动起来 言归正传┏ (゜ω゜)☞ 题目描述 小 C 想要成为一名 OIer&#xff0c;于是他提前学习数学&#xff0c;为 OI 做好铺垫。这一天&#xff0c;他的数学老师给了一道题&#xff1a;给定正整数 a&#xff0c;以及给定一个区间 …

789. 数的范围(C++和Python3)——2023.5.3打卡

文章目录 QuestionIdeasCode Question 给定一个按照升序排列的长度为 n 的整数数组&#xff0c;以及 q 个查询。 对于每个查询&#xff0c;返回一个元素 k 的起始位置和终止位置&#xff08;位置从 0 开始计数&#xff09;。 如果数组中不存在该元素&#xff0c;则返回 -1 -…

【VAR | 时间序列】应用VAR模型时的15个注意点

一、前言 向量自回归&#xff08;VAR,Vector Auto regression&#xff09;常用于预测相互联系的时间序列系统以及分析随机扰动对变量系统的动态影响。 VAR方法通过把系统中每一个内生变量,作为系统中所有内生变量的滞后值的函数来构造模型&#xff0c;从而回避了结构化模型的…

Java入门云计算:从基础到实践

前言 随着云计算的普及&#xff0c;越来越多的企业开始将应用部署在云上。作为广受欢迎的编程语言&#xff0c;Java在云计算中具有诸多优势。本文将为你介绍Java在云计算中的优势、Java做云计算的入门案例及分析&#xff0c;并教你如何使用Java实现简单的云计算应用。 云计算…

VMware12安装图解

目录 一、介绍VMware虚拟机 二、安装VMware12虚拟机 三、VMware虚拟机内部新建虚拟机 清理磁盘 一、介绍VMware虚拟机 VMware是一个虚拟机。 什么是虚拟机&#xff1f;字面意思‘虚拟’&#xff0c;那就不算是真的&#xff1b;‘机’可以理解为一台电脑或者一个电脑系统。…

Selenium实战教程系列(二)---元素定位

Selenium webdriver能够模拟人对浏览器进行操作的前提是界面元素的定位。元素的定位可以说是Selenium自动化脚本的基础。这一小节笔者将介绍如何在selenium中进行元素的定位。 定位元素的方法 Selenium中提供了以下定位元素的方法&#xff1a; 首先看一个HTML文件 test_page.…

《Netty》从零开始学netty源码(四十七)之PooledByteBuf的方法

setBytes() 从channel中读取数据并写到PooledByteBuf中&#xff0c;分配缓存的过程与getBytes一样&#xff0c;只是duplicate为false。 capacity() 动态更新容量&#xff0c;根据新传入的容量值更改length。 如果新容量值与旧值相同则无需扩容如果为非池化内存则根据新容量值…

TypeScript算法题实战——剑指 Offer篇(2)

Typescript 是 Javascript 的超集。Typescript 为 Javascript 增加类型能力&#xff0c;主要为了避免 JS 弱类型下产生的各种有意无意的问题。Typescript 的出现大大改善了开发体验&#xff0c;增强了代码的可维护性和稳定性&#xff0c;如今已被越来越多的大型前端项目选用。 …