第 69 课:Django 表单与表单处理
学习目标
- 理解并使用 Django 的
Form类创建 HTML 表单。 - 掌握在视图函数中处理表单数据的完整流程(GET/POST)。
- 能够使用 Django 表单系统进行简单的数据验证。
- 了解如何自定义表单的显示方式和错误信息。
核心概念
想象一下,你在网页上填写一个注册信息:输入用户名、密码、邮箱,然后点击"提交"。这个页面就是表单(Form),而服务器接收并处理这些信息的过程就是表单处理。在 Django 中,我们可以用 Python 代码来定义这个"表格"的结构和规则,系统会自动帮我们生成 HTML 并处理数据验证,这非常高效和安全。
1. 表单类 (Form Class)
这是 Django 表单的核心。我们通过继承 forms.Form 来定义一个表单类,里面定义了表单有哪些字段(字段类型就像文本框、下拉框),以及每个字段有什么规则(比如是否必填、最大长度)。
2. 表单的生命周期
一个典型的表单处理遵循 "GET - POST" 模式:
- GET 请求:当用户第一次访问页面时,服务器发送一个空白的、待填写的表单。
- POST 请求:当用户填写完表单并点击提交时,浏览器将填写的数据发送回服务器(使用 POST 方法),服务器处理这些数据。
3. CSRF 保护
Django 内置了强大的安全特性。在处理表单时,你必须包含 CSRF 令牌(CSRF Token)。这是一个安全令牌,用于验证请求确实来自你的网站,而不是来自其他恶意网站。在模板中,我们使用 {% csrf_token %} 标签来添加它。
代码示例
我们将创建一个简单的"联系我"表单。
第一步:定义表单类 (forms.py)
# 在你的应用目录下创建 forms.py 文件
from django import forms
class ContactForm(forms.Form):
# 定义表单字段:CharField 表示文本输入
name = forms.CharField(
label='您的姓名', # 显示在输入框旁边的标签
max_length=100, # 输入内容最大长度
required=True # 该字段为必填项
)
email = forms.EmailField(
label='电子邮箱',
required=True
)
message = forms.CharField(
label='留言内容',
widget=forms.Textarea, # 指定该字段的HTML小部件为文本域(多行文本框)
required=False # 该字段为非必填项
)
第二步:编写视图函数 (views.py)
# views.py
from django.shortcuts import render
from .forms import ContactForm # 导入我们定义的表单类
def contact_view(request):
if request.method == 'POST':
# 如果是 POST 请求,用提交的数据绑定表单
form = ContactForm(request.POST)
# 检查数据是否有效(包括所有字段是否符合规则)
if form.is_valid():
# 数据有效,可以进行后续操作,如保存到数据库、发送邮件等
# 这里我们先获取清理后的数据
name = form.cleaned_data['name']
email = form.cleaned_data['email']
message = form.cleaned_data.get('message', '') # 使用get避免KeyError
# 在真实项目中,这里会写保存或发送邮件的逻辑
print(f"收到来自 {name} ({email}) 的留言:{message}")
# 重定向到成功页面(这里为简单起见,仍渲染当前页面并添加成功消息)
context = {'form': ContactForm(), 'success': '留言发送成功!'}
return render(request, 'contact.html', context)
else:
# 如果是 GET 请求,创建一个空表单
form = ContactForm()
# 将表单实例传递给模板
context = {'form': form}
return render(request, 'contact.html', context)
第三步:创建模板 (contact.html)
<!-- templates/contact.html -->
<!DOCTYPE html>
<html>
<head>
<title>联系我们</title>
<style>
.errorlist { color: red; list-style: none; }
</style>
</head>
<body>
<h1>联系我们</h1>
{% if success %}
<p style="color: green;">{{ success }}</p>
{% endif %}
<form method="post">
{% csrf_token %} <!-- 关键:安全令牌 -->
{{ form.as_p }} <!-- Django 用段落格式自动渲染整个表单 -->
<button type="submit">提交留言</button>
</form>
<!-- 如果想更精细地控制,可以不用 `as_p`,而是手动渲染每个字段:
<p>
<label for="{{ form.name.id_for_label }}">{{ form.name.label }}</label>
{{ form.name }}
{{ form.name.errors }}
</p>
-->
</body>
</html>
第四步:配置 URL (urls.py)
# urls.py (在你的应用目录或项目主urls文件中)
from django.urls import path
from . import views
urlpatterns = [
path('contact/', views.contact_view, name='contact'),
]
实践练习
-
基础练习:基于上述代码,添加一个"电话号码"字段(
forms.CharField),并将其设为非必填。在视图中打印这个号码(如果提供了的话)。 -
进阶练习:修改模板,不使用
{{ form.as_p }},而是手动渲染name和email字段,并在每个字段下方显示验证错误信息(例如{{ form.name.errors }})。 -
挑战练习:创建一个用户注册表单(
UserRegisterForm),包含username,password,confirm_password三个字段。在视图的is_valid()检查之后,增加一个自定义验证:检查两次输入的密码是否一致。如果不一致,将错误信息添加到表单的错误字典中(可以使用form.add_error('confirm_password', '两次输入的密码不一致'))。
常见错误
- 忘记
{% csrf_token %}:这是最常犯的错误之一。如果你的表单提交后收到 403 Forbidden 错误,或者控制台报错CSRF verification failed,请检查模板中是否包含了这个标签。 - 在 GET 请求中处理 POST 数据:初学者有时会混淆
request.method的判断。记住:只有POST请求才包含用户提交的表单数据(request.POST)。在GET请求中访问request.POST是无效的。 - 过早访问
cleaned_data:必须先调用form.is_valid()对数据进行验证和清洗。只有在表单验证通过后,才能安全地使用form.cleaned_data获取数据,否则可能引发异常。 - 字段命名冲突:确保你的表单字段名(如
name)不会与 Django 模型或表单中内置的属性(如clean)冲突。
小结
在本课中,我们学习了 Django 表单处理的完整流程:
- 定义:通过
forms.Form子类定义表单的字段和验证规则。 - 渲染:在视图中创建表单实例并传递给模板,模板中使用
{{ form }}相关标签生成 HTML。 - 处理:在视图中根据请求方法(GET/POST)进行分支处理,使用
form.is_valid()验证数据,并通过cleaned_data安全地获取清洗后的数据。 - 安全:始终使用
{% csrf_token %}保护你的表单免受跨站请求伪造攻击。
掌握表单处理是构建动态、可交互 Web 应用的基础。下一课,我们将学习如何将表单与用户认证系统结合,实现真正的用户注册和登录功能。