Django的forms
模块提供了用于处理表单数据的功能,它对表单创建、验证和数据处理进行了封装,使得开发者可以方便地处理表单类型请求,这篇笔记我们对forms
模块进行简单介绍。
注意:forms
模块通常是和模板引擎结合使用的,和模板引擎技术类似,forms
也是个相对过时的技术,它主要用于传统的服务端MVC工程。在前后端分离项目中,数据封装和验证功能通常由DRF的序列化器实现。
我们这里使用一个例子工程,工程目录结构如下,表单类我们这里将其全部放置到forms.py
中。
|_ demo01 # APP子模块
|_ views.py # 视图函数
|_ models.py # 数据模型
|_ forms.py # 表单模块
|_ templates # 模板文件夹
|_ index.html # 模板文件
demo01/models.py
from django.db import models
class ClassRoom(models.Model):
class Meta:
verbose_name = '教室'
verbose_name_plural = '教室'
room_code = models.CharField(max_length=10, verbose_name='教室号')
def __str__(self):
return self.room_code
class Student(models.Model):
class Meta:
verbose_name = '学生'
verbose_name_plural = '学生'
stu_code = models.CharField(max_length=10, unique=True, verbose_name='学号')
name = models.CharField(max_length=20, verbose_name='学生姓名')
age = models.IntegerField(default=-1, verbose_name='年龄')
class_room = models.ForeignKey(ClassRoom, null=True, on_delete=models.DO_NOTHING, related_name='students',
verbose_name='所在教室')
数据模型中,我们有ClassRoom
教室模型和Student
学生模型,它们通过外键字段class_room
关联,具有一对多关系。
demo01/forms.py
from django import forms
from demo01.models import *
class StudentForm(forms.Form):
stu_code = forms.CharField(max_length=10, label='学号')
name = forms.CharField(max_length=20, label='学生姓名')
age = forms.IntegerField(label='年龄')
class_room = forms.ModelChoiceField(queryset=ClassRoom.objects.all(), label='所在教室')
表单类中,我们定义了4个字段,分别是stu_code
学号、name
姓名、age
年龄和class_room
所在教室,其中class_room
字段对应数据模型的外键字段。对于普通字段我们使用了CharField
和IntegerField
表示需要用户输入字符串和数字,外键字段我们使用ModelChoiceField
字段类型,它表示一个模型选择字段,queryset
参数指定了查询集,这里我们查询了所有教室。表单字段中,我们还用到了max_length
命名参数,它用于表单校验,此外在渲染表单时,对应HTML的<input>
标签也会添加相关最大长度限制。
demo01/views.py
from django.shortcuts import render
from demo01.forms import StudentForm
def index(request):
if request.method == 'POST':
form = StudentForm(request.POST)
if form.is_valid():
print(form.cleaned_data.get('stu_code'))
print(form.cleaned_data.get('name'))
print(form.cleaned_data.get('age'))
print(form.cleaned_data.get('class_room').room_code)
return render(request, 'success.html')
else:
return render(request, 'index.html', {
'form': form
})
else:
form = StudentForm()
return render(request, 'index.html', {
'form': form
})
视图函数index()
中,当浏览器发起GET请求时,我们返回index.html
模板页面,其中渲染了空表单;当浏览器发起POST请求时,我们使用forms
模块自动解析表单请求,如果表单验证通过则重定向到成功页面,如果表单验证不通过则继续将表单传入index.html
模板页面,模板会自动回显相关错误信息。由于模板页面上总是会用到form
对象,因此其实我们可以看到,代码中任何时候我们都会将forms
对象传入模板,GET请求时也会传一个空的form
对象,大多数Web开发框架其实都是类似的使用方式。
demo01/templates/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Student</title>
</head>
<body>
<form method="post">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<button type="submit">提交</button>
</form>
</body>
</html>
模板中,我们创建了<form>
标签,它使用POST提交表单,此外我们没有指定action
因此它将默认提交表单到当前路径(如果我们要提交到其他路径则需要指定action
)。模板中我们还调用了form.as_table
方法,它会将表单渲染成一个表格,最终效果如下图所示。
它实际上渲染的HTML结果如下。