python3之Django表单(一)
1、html中的表单
在html种,表单是在<form>...</form>种的元素,它允许用户输入文本,选择选项,操作对象等,然后发送这些数据到服务器
表单元素允许用户在表单种输入内容如,文本域(textarea)、下拉列表、单选框(radio-buttons)、复选框(checkboxes)等。
大多数情况下被用到的表单标签是输入标签(<input>),输入类型是由类型属性(type)定义的,大多数经常被用到的输入类型下面做简单介绍:
(1)文本域(text fields)
文本域通过<input type="text">标签来设定,当用户要在表单种输入字母,数字等内容是,就会用到文本域,在大多数浏览器种,文本域的缺省宽度是20个字符:
<form> 姓名:<input type="text" name="username"><br> </form>
(2)密码字段
密码字段通过标签<input type="password">来定义,密码字段字符不会明文显示,而是以星号或圆点替代:
<form> 姓名:<input type="text" name="username"><br> 密码:<input type="password" name="password"> </form>
(3)单选按钮(radio buttons)
<input type="radio">标签定义了表单单选框选项
<form> 姓名:<input type="text" name="username"><br> 密码:<input type="password" name="password"><br> 性别:<input type="radio" name="sex" value="man">男<input type="radio" name="sex" value="weman">女<br> </form>
(4)复选框(checkboxes)
<input type="checkbox"定义了复选框,用户可以从若干个给定的选择种选择多个
<form> 姓名:<input type="text" name="username"><br> 密码:<input type="password" name="password"><br> 性别:<input type="radio" name="sex" value="man">男<input type="radio" name="sex" value="weman">女<br> 爱好:<input type="checkbox" name="vehicle" value="yundong">运动 <input type="checkbox" name="vehicle" value="youxi">游戏 <input type="checkbox" name="vehicle" value="xuexi">学习 </form>
(5)提交按钮(submit button)
<input type="submit">定义了提交按钮,当用户单击确认按钮时,表单的内容就会被传送到动作属性定义的目的文件中
<form action="index.html" method="post"> 姓名:<input type="text" name="username"><br> 密码:<input type="password" name="password"><br> 性别:<input type="radio" name="sex" value="man">男<input type="radio" name="sex" value="weman">女<br> 爱好:<input type="checkbox" name="vehicle" value="yundong">运动 <input type="checkbox" name="vehicle" value="youxi">游戏 <input type="checkbox" name="vehicle" value="xuexi">学习<br> <input type="submit" value="提交"> </form>
浏览器表单中的数据会发往action属性指定的url,并且使用它的method属性指定的http方法post,当点击submit类型的提交时,会将数据发送到index.html中。
html5有许多新的input类型:
color类型选取颜色,date类型日期选择器,datetime-local类型选择一个日期和时间,email类型用于e-mail地址的输入域,month类型允许选择一个月份,number类型用于数值的输入域,rang类型定义一定范围内数字的输入域,显示为滑动条可设置最大值max和最小值min,search类型用于搜索域,tel类型定义电话号码字段,time类型定义一个时间选择,url类型用于url地址的输入域,week类型允许选择周和年。
处理表单时只会用到get和post两种http方法,get方法会将提交的数据捆绑到url中,而post通过加密的方式在后台提交
2、django中的表单
django会处理涉及表单的三个部分:
准备并重组数据,以便下一步的渲染;为数据创建html表单;接收并处理客户端提交的表单以及数据。
django表单系统的核心组件是form类,form类描述一张表单并决定它如何工作并呈现
form类,类似于模型类的字段映射到数据库字段的方式,表单类的字段会映射到html表单的<input>元素,表单字段本身也是类,它们管理表单数据并提交表单执行验证,在浏览器中表单字段以html控件的形式展现给我们,在django中每个字段类型都有与之匹配的控件类,在必要时也可以覆盖
在django中渲染一个对象的过程通常为:在视图中获取数据,然后将数据传递给模板,使用模板变量将数据扩展到html标记,下面我们在django中构建表单
在app中新建forms.py文件:
from django import forms #首先它继承form类,然后通过控件类charfield定义文本域并指定属性 class indexform(forms.form): username = forms.charfield(label='姓名',max_length=100)
然后在编辑视图并引入表单类:
#views.py from django.shortcuts import render from django.http import httpresponse from .forms import indexform #新建视图函数处理表单,首先判断提交类型为post则通过表单类接收post请求数据并填充表单类,然后判断数据是否有效并提交到后台,此处做演示只做判断并提示接收成功,
#如果提交类型不为post则创建空表单通过变量传递给模板 def get_name(request): if request.method == 'post': form = indexform(request.post) print(form) if form.is_valid(): return httpresponse('提交到后台成功!') else: form = indexform() return render(request,'index.html',{'form':form})
表单类生成的数据如下:
<tr><th><label for="id_username">姓名:</label></th><td><input type="text" name="username" value="root" maxlength="100" required id="id_username"></td></tr>
在模板中只需简单的配置form标签并接收变量,注意表单不包含提交标签需要在模板中自己创建
<form action="{% url 'formtest' %}" method="post"> {% csrf_token %} #此处为跨站请求伪造保护功能django自提供 {{ form }} <input type="submit" value="提交"> </form>
页面程序效果:
<form action="/" method="post"> <input type="hidden" name="csrfmiddlewaretoken" value="e9je91nyzzfwx83yxqbsihyyjh3g4tsiz22zajeahsfknnzpjaincvd1ihzanc4b"> <label for="id_username">姓名:</label><input type="text" name="username" maxlength="100" required="" id="id_username"> <input type="submit" value="提交"> </form>
在模板中我们只需将表单在上下问中进行渲染,来得到对应的标签元素,如上面的form变量渲染{{ form }}
但在表单渲染选项还可以使用其他渲染方式:
{{ form.as_table }}包装在<tr>标记中的表格单元格显示数据,但必须自己提供外层<table>元素
{{ form.as_p }}包裹在<p>标记中的显示数据
{{ form.as_ul }}包裹在<li>标记中显示数据,但必须自己提供外层<ul>元素
手动渲染字段:
循环遍历每个字段对字段属性手动渲染,如下field.errors输出包含改字段验证的错误信息,field.label_tag为带<label>标签的label值
#遍历表单字段 <form action="{% url 'index' %}" method="post"> {% csrf_token %} {% for field in form %} {{ field.errors }} {{ field.label_tag }} {{ field }}<br> {% endfor %} <input type="submit" value="提交"> </form> #渲染效果 <form action="/" method="post"> <input type="hidden" name="csrfmiddlewaretoken" value="benu1pciyh6xktsxa7cqyr8wwwiyvae7w7gps7tkgagla8oowrjls5nzvweiojqq"> <label for="id_subject">subject:</label> <input type="text" name="subject" maxlength="100" required="" id="id_subject"><br> <label for="id_message">message:</label> <textarea name="message" cols="40" rows="10" required="" id="id_message"></textarea><br> <label for="id_sender">sender:</label> <input type="email" name="sender" required="" id="id_sender"><br> <label for="id_cc_myself">cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"><br> <input type="submit" value="提交"> </form>
field.label_tag:输出field的label元素,如:<label for="id_subject">subject:</label>
field:输出field的input,如:<input type="text" name="subject" maxlength="100" required="" id="id_subject">
field.errors:输出field的errors元素,一般在form表单验证出错时显示
field.id_for_label:输出字段的id值
field.value:输出字段填充的值
field.html_name:输出字段的名称
field.help_text:输出与该字段的帮助文本
field.is_hidden:如果是隐藏字段属性值为true否则为false
3、表单集
formset表单集是多个表单的集合,formset在web开发中应用很普遍,它可以让用户在同一个页面提交多张表单,一键添加多个数据
django针对不同的formset提供了三种方法:formet_factory,modelformset_factory和inlineformset_factory
(1)使用formset_factory
对应继承forms.form的自定义表单,我们可以使用formset_factory,通过设置extra指定表单数量,max_num指定表单数量最大值
首先创建表单并使用formset_factory方法指定创建表单集并指定表单数量
#forms.py from django import forms from django.forms import formset_factory class registerform(forms.form): username = forms.charfield(max_length=120) age = forms.integerfield() pub_date = forms.datefield(required=false) registerformset = formset_factory(registerform,extra=3,max_num=5)
在视图views.py里使用formset
#views.py from django.shortcuts import render,httpresponse from .forms import registerformset def register(request): if request.method == 'post': formset = registerformset(request.post,request.files) if formset.is_valid(): return httpresponse('formset is ok') else: formset = registerformset() return render(request,'register.html',context={'formset':formset})
最后在模版中应用表单即可
<form action="{% url 'register' %}" method="post"> {{ formset.management_form }} {% for form in formset %} {{ form.as_p }} {% endfor %} </form>
4、从模型创建表单
首先创建model模型:
from django.db import models from django.utils import timezone title_choices = ( ('mr','mr.'), ('mrs','mrs.'), ('ms','ms.'), ) class author(models.model): name = models.charfield(max_length=100,verbose_name='姓名') title = models.charfield(max_length=3,choices=title_choices,verbose_name='标题') birth_date = models.datefield(default=timezone.now,blank=true,null=true,verbose_name="创建时间") def __str__(self): return self.name
根据模型创建表单文件:
#forms.py #导入模型表单类 from django.forms import modelform from .models import author #继承模型表单类创建表单 class authorform(modelform): class meta: model = author #指定model fields = ['name','title','birth_date'] #指定要显示的字段,全显示可使用"__all__"
在通过模型创建表单时,我们只需继承django的模型表单类,然后重写它的属性即可,model指定要创建表单的模型,fields指定显示的模型字段,全显示可以用“__all__"代替,还有其他的类属性exclude指定排除的字段,labels指定提示信息,help_texts指定帮助提示信息,widgets指定自定义插件,error_messages自定义错误信息,field_classes自定义字段类,localized_fields本地化时区时间,根据setting中time_zone设置的不同时区显示时间
from django import forms from django.forms import modelform from .models import author class authorform(modelform): class meta: model = author fields = ['name','title','birth_date'] widgets = { 'title':forms.textarea(attrs={'cols':80,'rows':20}) } #覆盖重写title字段的类型 labels = { 'name':'作者', 'title':'头衔', 'birth_date':'出生日期', } error_messages = { 'name':{ 'max_length':'名字长度在15个字符内', } }
在django中的模型字段和表单字段的字段类型定义都差不多,比较特殊的是foreignkey和manytomanyfield模型字段在表单中的字段类型会有所不同:
foreignkey由django.forms.modelchoicefield表示,它是一个choicefield,其选项是一个模型queryset
manytomanyfield由django.forms.modelmultiplechoicefield表示,它是一个multiplechoicefield,其选项为一个模型queryset
另外,每个生成的表单字段的属性设置如下:
如果模型字段设置了blank=true,那么表单字段的required属性被设置为false,否知为true
表单字段的label设置为模型字段的verbose_name,并且首字母大写
表单字段的help_text设置为模型字段的help_text
如果模型字段设置了choices,那么表单字段的widget会被设置为select,其选项来自模型字段的choices,这些选项通常包含一个默认选中的空选项,如果字段设置了必填,则会强制用户进行选项,如果模型字段设置了blank=false以及一个明确的default值,则表单字段中不会包含空选项
在视图中使用表单:
#views.py from django.shortcuts import render,httpresponse from .forms import authorform from .models import author def test(request): if request.method == 'post': author_form = authorform(request.post) if author_form.is_valid(): author_form.save(commit=true) return httpresponse('提交成功') else: author_form = authorform() obj = author.objects.all() return render(request,'test.html',{"author_form":author_form,'obj':obj})
views.py中使用modelform的save()方法将表单数据保存到数据库中,参数commit为true时写如数据库,如果为false则创建一个model对象但不保存到数据库中,如果要更新某个对象可以使用save的instance参数来指定要更新的model对象
在模板中提交并展示数据:
#test.html <body> <h2>author form:</h2> <form action="{% url 'test' %}" method="post"> {% csrf_token %} {{ author_form }} <input type="submit" value="提交"> </form> <h2>author form output:</h2> <ul> {% for i in obj %} <li>{{ i.id }}:{{ i.name }}:{{ i.title }}:{{ i.birth_date }}</li> {% endfor %} </ul> </body>
表单模板modelform中有一个工厂函数可以直接通过model创建表单modelform_factory(),在不需要很多自定义的情况下是很方便的
from .models import author from django import forms from django.forms.models import modelformset_factory modelform_author = modelformset_factory(model=author,fields=('__all__'),widgets={'title':forms.textarea()})