69·模块十三:Web开发基础进阶

Django 表单与表单处理

djangoforms

第 69 课:Django 表单与表单处理

学习目标

  1. 理解并使用 Django 的 Form 类创建 HTML 表单。
  2. 掌握在视图函数中处理表单数据的完整流程(GET/POST)。
  3. 能够使用 Django 表单系统进行简单的数据验证。
  4. 了解如何自定义表单的显示方式和错误信息。

核心概念

想象一下,你在网页上填写一个注册信息:输入用户名、密码、邮箱,然后点击"提交"。这个页面就是表单(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'),
]

实践练习

  1. 基础练习:基于上述代码,添加一个"电话号码"字段(forms.CharField),并将其设为非必填。在视图中打印这个号码(如果提供了的话)。

  2. 进阶练习:修改模板,不使用 {{ form.as_p }},而是手动渲染 nameemail 字段,并在每个字段下方显示验证错误信息(例如 {{ form.name.errors }})。

  3. 挑战练习:创建一个用户注册表单(UserRegisterForm),包含 username, password, confirm_password 三个字段。在视图的 is_valid() 检查之后,增加一个自定义验证:检查两次输入的密码是否一致。如果不一致,将错误信息添加到表单的错误字典中(可以使用 form.add_error('confirm_password', '两次输入的密码不一致'))。

常见错误

  1. 忘记 {% csrf_token %}:这是最常犯的错误之一。如果你的表单提交后收到 403 Forbidden 错误,或者控制台报错 CSRF verification failed,请检查模板中是否包含了这个标签。
  2. 在 GET 请求中处理 POST 数据:初学者有时会混淆 request.method 的判断。记住:只有 POST 请求才包含用户提交的表单数据(request.POST)。在 GET 请求中访问 request.POST 是无效的。
  3. 过早访问 cleaned_data:必须先调用 form.is_valid() 对数据进行验证和清洗。只有在表单验证通过后,才能安全地使用 form.cleaned_data 获取数据,否则可能引发异常。
  4. 字段命名冲突:确保你的表单字段名(如 name)不会与 Django 模型或表单中内置的属性(如 clean)冲突。

小结

在本课中,我们学习了 Django 表单处理的完整流程:

  • 定义:通过 forms.Form 子类定义表单的字段和验证规则。
  • 渲染:在视图中创建表单实例并传递给模板,模板中使用 {{ form }} 相关标签生成 HTML。
  • 处理:在视图中根据请求方法(GET/POST)进行分支处理,使用 form.is_valid() 验证数据,并通过 cleaned_data 安全地获取清洗后的数据。
  • 安全:始终使用 {% csrf_token %} 保护你的表单免受跨站请求伪造攻击。

掌握表单处理是构建动态、可交互 Web 应用的基础。下一课,我们将学习如何将表单与用户认证系统结合,实现真正的用户注册和登录功能。

练习编辑器

python
Loading...

继续学习

完成本课后,建议继续学习下一课「Django 用户认证系统」 以巩固所学知识。