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中录入的邮件信息是一致的。

相关推荐
觅远5 分钟前
python+PyMuPDF库:(一)创建pdf文件及内容读取和写入
开发语言·python·pdf
MinIO官方账号40 分钟前
使用亚马逊针对 PyTorch 和 MinIO 的 S3 连接器实现可迭代式数据集
人工智能·pytorch·python
四口鲸鱼爱吃盐43 分钟前
Pytorch | 利用IE-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
人工智能·pytorch·python·深度学习·计算机视觉
四口鲸鱼爱吃盐1 小时前
Pytorch | 利用EMI-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
人工智能·pytorch·python
两点王爷1 小时前
Java读取csv文件内容,保存到sqlite数据库中
java·数据库·sqlite·csv
游客5201 小时前
自动化办公-合并多个excel
开发语言·python·自动化·excel
豌豆花下猫2 小时前
Python 潮流周刊#83:uv 的使用技巧(摘要)
后端·python·ai
LuiChun2 小时前
docker django uwsgi 报错记录
docker·容器·django
凡人的AI工具箱2 小时前
每天40分玩转Django:Django部署概述
开发语言·数据库·后端·python·django
RacheV+TNY2642782 小时前
深度解析:电商平台API接口的安全挑战与应对策略
人工智能·python·自动化·api