Django Form类详解

【图书介绍】《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 }}:&nbsp;&nbsp;{{ 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 }}&nbsp;:&nbsp;{{ 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中录入的邮件信息是一致的。

相关推荐
lkx097887 小时前
第九天的尝试
python
佩奇的技术笔记7 小时前
Python入门手册:Python基础语法
开发语言·python
白白糖8 小时前
相同,对称,平衡,右视图(二叉树)
python·算法·二叉树·力扣
学习baba酱8 小时前
关于Python+selenium+chrome编译为exe更换电脑无法打开问题
chrome·python·selenium
几道之旅9 小时前
pytdx数据获取:在线获取和离线获取(8年前的东西,还能用吗?)
python
jay神9 小时前
基于Python+YOLO模型的手势识别系统
开发语言·python·深度学习·yolo·手势识别系统
点云兔子10 小时前
使用 OpenCV 实现 ArUco 码识别与坐标轴绘制
人工智能·python·opencv
覆东流10 小时前
Python语法特点与编码规范
python
Want59511 小时前
Python炫酷烟花
开发语言·python·pygame
老歌老听老掉牙11 小时前
Python 脚本执行命令的深度探索:方法、示例与最佳实践
python·命令