【图书介绍】《Django 5企业级Web应用开发实战(视频教学版)》_django 5企业级web应用开发实战(视频教学版)-CSDN博客
《Django 5企业级Web应用开发实战(视频教学版)》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com)
本节主要详细介绍Django框架中Form类的内容。Form类与Model类紧密关联,是构建Web应用的内部核心部件。
6.3.1 模型与Form类
在Django框架中,所有Form类均是作为django.forms.Form类或者django.forms.ModelForm类的子类来创建的。可以把ModelForm理解为Form类的子类。
实际上Form类和ModelForm类从BaseForm类继承了(私有方式)其通用功能,设计使用时一般是不用去关心这个实现细节的。感兴趣的读者可以去研究一下Django框架模板的源代码,相信会学习到不少知识。
Django框架表单如果是要直接用来添加或编辑Django模型的,则一般要使用ModelForm类,这样既可以省时省力,又可以节省代码,因为其会根据Model类构建一份对应字段及其属性的表单。
6.3.2 绑定的和未绑定的表单实例
在Django框架表单中,绑定的和未绑定的表单实例之间的显著区别如下:
- 未绑定的表单没有与其关联的数据。当渲染到页面模板时,其会是空的或者包含默认值。
- 绑定的表单拥有已提交的数据,因此可以用来判断数据是否合法。如果渲染了一个非法绑定的表单,则其将会包含内联的错误信息,告知设计人员要纠正哪些数据。
实际开发中,Form表单的is_bound属性将会告诉设计人员,一个表单是否具有绑定的数据。
6.3.3 表单字段与Widget控件
在Django框架表单中,为设计人员内置了许多表单字段,提供了非常完整的表单设计功能。一份比较完整的字段清单如下:
BooleanField
CharField
ChoiceField
TypedChoiceField
DateField
DateTimeField
DecimalField
DurationField
EmailField
FileField
FilePathField
FloatField
ImageField
IntegerField
JSONField
GenericIPAddressField
MultipleChoiceField
TypedMultipleChoiceField
NullBooleanField
RegexField
SlugField
TimeField
URLField
UUIDField
ComboField
MultiValueField
SplitDateTimeField
ModelChoiceField
ModelMultipleChoiceField
其中,每一个表单字段的类型都对应一种Widget控件。Widget控件是一种内建于Django框架中的类,每一种Widget类均对应HMTL语言中的一种<input>元素类型。例如,CharField字段对应于<input type="text">元素类型。
设计人员需要在HTML模板中使用什么类型的<input>元素,就需要在Django表单字段中选择相应的"XXXField"。例如,如果需要一个<input type="text">元素,就可以选择一个CharField。
下面,我们通过多种Form类字段构建一个"联系人邮件信息"表单。Form类还是定义在表单模块(forms.py)中,具体代码如下:
【代码6-6】(详见源代码FormSite项目的formapp/forms.py文件)
01 from django import forms
02
03 # Form类: ContactForm
04 class ContactForm(forms.Form):
05 subject = forms.CharField(label='Subject', max_length=64)
06 message = forms.CharField(label='Message', widget=forms.Textarea)
07 sender = forms.EmailField(label='Sender', max_length=64)
08 cc_myself = forms.BooleanField(required=False)
【代码分析】
在第01行代码中,通过import关键字引入forms模块。
在第04~08行代码中,通过class定义表单类ContactForm,其中内置了多种类型的表单字段。表单字段的详细说明如下:
- 在第05行代码中,通过CharField字段类型定义了一个表单字段subject,对应于HTML表单<form>标签中的"标题"文本输入框。
- 在第06行代码中,通过CharField字段类型定义了一个表单字段message,Widget控件定义为Textarea控件,对应于HTML表单<form>标签中的"邮件信息"文本输入框。
- 在第07行代码中,通过EmailField字段类型定义了一个表单字段sender,对应于HTML表单<form>标签中的"邮件目标发送地址"文本输入框。
- 在第08行代码中,通过BooleanField字段类型定义了一个表单字段cc_myself,对应于HTML表单<form>标签中的抄送自己单选类型控件。
无论用表单提交了什么数据,一旦通过调用is_valid()方法验证成功(返回True),已验证的表单数据都将被放到form.cleaned_data字典中,而且这些数据已经转换为了可以直接调用的Python 类型。
Django框架表单的实例化代码还是放在views.py视图文件中,且与forms.py表单文件处于同一级目录。表单类ContactForm的实例化代码如下:
【代码6-7】(详见源代码FormSite项目的formapp/views.py文件)
01 from .forms import ContactForm
02 # 创建表单视图
03 def contact(request):
04 # 如果这是一个POST请求,我们需要处理表单数据
05 if request.method == 'POST':
06 # 创建一个表单实例并用请求中的数据填充
07 form = ContactForm(request.POST)
08 # 检查表单实例是否有效
09 if form.is_valid():
10 # 按照要求处理form.cleaned_data中的数据
11 context = {}
12 subject = form.cleaned_data['subject']
13 message = form.cleaned_data['message']
14 sender = form.cleaned_data['sender']
15 cc_myself = form.cleaned_data['cc_myself']
16 context['subject'] = subject
17 context['message'] = message
18 context['sender'] = sender
19 context['cc_myself'] = cc_myself
20 # 重定向到一个新的URL地址
21 return render(request, 'show_contact.html', {'contact': context})
22 # 如果是GET(或其他任何方法),我们将创建一个空白表单
23 else:
24 form = ContactForm()
25 # 在HTML模板中渲染表单
26 return render(request, 'contact.html', {'form': form})
【代码分析】
在第01行代码中,通过import关键字引入ContactForm表单类。
在第03~26行代码中,定义了一个视图函数contact,对表单类ContactForm进行了实例化操作。详细说明如下:
- 在第05行代码中,通过if条件语句判断HTTP请求方法,如果为POST方法,则继续执行后面代码去接收用户提交的数据;如果为GET方法,则直接跳转到第23行代码,执行第24行代码返回空的表单实例from,让用户去录入数据再进行提交。
- 在第07行代码中,先通过request获取表单数据,再通过ContactForm表单类创建表单实例form。
- 在第09行代码中,通过if条件语句对表单实例form进行验证,如果所有的表单字段均有效,则继续执行下面的代码。
- 在第12~15行代码中,通过表单实例form对象的cleaned_data属性获取表单字段数据。
- 在第16~19行代码中,将获取的字段数据保存在上下文变量context中。
- 在第21行代码中,将上下文变量context保存为字典类型变量contact,通过render()方法传递表单数据contact到新的页面中进行显示。
- 在第26行代码中,将表单实例form渲染到表单模板contact.html中。
对于模板的处理就相对简单得多。表单类ContactForm的模板代码如下:
【代码6-8】(详见源代码FormSite项目的formapp/templates/contact.html文件)
01 <!DOCTYPE html>
02 <html lang="en">
03 <head>
04 <meta charset="UTF-8">
05 <link rel="stylesheet" type="text/css" href="/static/css/mystyle.css"/>
06 <title>Contact Form</title>
07 </head>
08 <body>
09
10 <h3>Contact Form</h3>
11
12 <form action="#" method="post">
13 {% csrf_token %}
14 {% for f in form %}
15 {{ f.label }}: {{ f }}<br><br>
16 {% endfor %}
17 <input type="submit" value="Submit" /><br>
18 </form>
19
20 </body>
21 </html>
【代码分析】
在第12~18行代码中,通过<form>标签定义了一个表单模板,method属性定义为POST方法。
在第13行代码中,通过{% csrf_token %}模板标签为表单增加防护功能。
在第14~16行代码中,通过{% for-endfor %}模板标签遍历表单实例form的每一项,并在页面模板中进行显示。
在第17行代码中,定义了表单的提交按钮<input type="submit" />。
在前面的视图处理中,定义了一个用于显示表单提交数据的HTML模板,具体代码如下:
【代码6-9】(详见源代码FormSite项目的formapp/templates/show_contact.html文件)
01 <!DOCTYPE html>
02 <html lang="en">
03 <head>
04 <meta charset="UTF-8">
05 <link rel="stylesheet" type="text/css" href="/static/css/mystyle.css"/>
06 <title>Show Userinfo</title>
07 </head>
08 <body>
09
10 <h3>Contact Info</h3>
11 <p>
12 contact (items):<br>
13 {% for key,value in contact.items %}
14 {{ key }} : {{ value }}<br>
15 {% endfor %}
16 </p>
17
18 </body>
19 </html>
【代码分析】
在第13~15行代码中,通过{% for-endfor %}模板标签遍历字典类型的上下文变量contact中的每一项,并依次在页面模板中进行显示。
现在,我们测试一下上面基于Django框架Form类构建的"联系人邮件信息"Web应用。
首先,通过FireFox浏览器打开一下FormSite项目中定义的contact表单应用地址,具体如图6.4中的箭头和标识所示,HTML模板(contact.html)中显示了从表单模块(forms.py)和视图模块(views.py)中传递过来的空白的"用户信息"表单。
然后,在空白表单中录入用户信息,具体如图6.5中的箭头和标识所示,录入相关邮件信息后,直接单击Submit按钮进行提交。表单提交后的页面效果如图6.6所示,页面中显示了contact字典对象的内容,与图6.5中录入的邮件信息是一致的。