使用表单 — Django 6.0.4 documentation(2026)
创始人
2026-06-01 18:22:11
0
Django教程

使用表单

关于本页文档

本页文档介绍了Web表单的基本内容以及它们在Django中是如何处理的。想更详细的了解表单的API,参见 表单 API表单字段 ,以及 表单和字段验证

除非您计划搭建的网站和应用只发布内容且不接收访问者的输入,否则您就需要理解和使用表单。

Django提供了一系列的工具和库来帮助您构建表单来接收网站访客的输入,然后处理以及响应这些输入。

HTML表单

在HTML中,表单是在

...
中的一些元素,它允许访客做一些类似输入文本、选择选项、操作对象或空间等动作,然后发送这些信息到服务端。

一些表单界面元素(文本框或复选框)内置在HTML中。其他会更复杂些;像弹出日期选择或者允许您移动滑块或者操作控件,一般通过使用JavaScript,CSS以及HTML表单中的 元素来实现这些效果。

和它的元素 一样,表单必须指定两样东西:

  • 何地:负责响应用户输入数据的URL地址

  • 如何:数据请求使用的HTTP方法。

例如,Django admin的登录表单包含了一些 元素:用户名用 type="text" ,密码用 type="password" ,登录按钮用 type="submit" 。它还包含一些用户看不到的隐藏文本字段,Django用它们来决定下一步行为。

它还告诉浏览器表单数据应该发往

action 属性指定的URL—— /admin/ ,并且应该使用它的 method 属性指定的HTTP方法—— post

type="submit" value="Log in"> 元素被触发的时候,数据会发送到 /admin/

GETPOST

处理表单时只会用到 GETPOST 两种HTTP方法。

Django的登录表单使用 POST 方法传输数据,在这个方法中浏览器会封装表单数据,为了传输会进行编码,然后发送到服务端并接收它的响应。

相比之下,GET 方法将提交的数据捆绑到一个字符串中,并用它来组成一个URL。该URL包含了数据要发送的地址以及一些键值对应的数据。如果您在Django文档中进行一次搜索,就会看到这点,它会生成一个形似 https://docs.djangoproject.com/search/?q=forms&release=1 的URL。

GETPOST 通常用于不同的目的。

任何可能用于更改系统状态的请求应该使用 POST —— 比如一个更改数据库的请求。GET 应该只被用于不会影响系统状态的请求。

GET 也不适合密码表格,因为密码会出现在 URL 中,因此也会出现在浏览器历史和服务器日志中,都是纯文本。它也不适合于大量的数据,或二进制数据,如图像。一个使用 GET 请求管理表单的网络应用程序是一个安全风险:攻击者很容易模仿表单的请求来获得对系统敏感部分的访问。POST,加上其他保护措施,如 Django 的 CSRF 保护,可以对访问进行更多控制。

另一方面, GET 方法适用于诸如网页搜索表单这样的内容,因为这类呈现为一个 GET 请求的URL很容易被存为书签、分享或重新提交。

Django在表单中的角色

处理表单是一件挺复杂的事情。想想看Django的admin,许多不同类型的数据可能需要在一张表单中准备显示,渲染成HTML,使用方便的界面进行编辑,传到服务器,验证和清理数据,然后保存或跳过进行下一步处理。

Django的表单功能可以简化和自动化上述工作的大部分内容,并且也能比大多数程序员自己编写代码去实现来的更安全些。

Django会处理涉及表单的三个不同部分:

  • 准备并重组数据,以便下一步的渲染

  • 为数据创建HTML 表单

  • 接收并处理客户端提交的表单及数据

可以 手动编写代码来实现,但Django 可以帮你完成所有这些工作。

Django 中的表单

我们已经简单的描述过了HTML 表单,但是一个HTML 只是其所需的一部分。

在网络应用的上下文中,“表单”可能指的是那个HTML ,或者指产生它的 Django Form,或者指它提交时返回的结构化数据,或者指这些部分的端到端工作集合。

Django的 Form

Django表单系统的核心组件是 Form 类。它与Django模型描述对象的逻辑结构、行为以及它呈现给我们内容的形式的方式大致相同, Form 类描述一张表单并决定它如何工作及呈现。

类似于模型类的字段映射到数据库字段的方式,表单类的字段会映射到HTML表单的 元素。 ModelForm 通过 Form 映射模型类的字段到HTML表单的 元素,Django admin就基于此。

表单字段本身也是类;他们管理表单数据并在提交表单时执行验证。 DateFieldFileField 处理的数据类型差别很大,所以必须用来处理不同的字段。

在浏览器中,表单字段以HTML“控件”(用户界面的一个片段)的形式展现给我们。每个字段类型都有与之相匹配的 控件类 ,但必要时可以覆盖。

实例化、处理和渲染表单

在Django中渲染一个对象的时候,我们通常:

  1. 在视图中获取它(例如从数据库中取出)

  2. 将它传递给模板上下文

  3. 使用模板变量将它扩展为HTML标记

在模板中渲染表单几乎与渲染任何其他类型的对象的一样,但是存在一些关键性的差异。

如果模型实例不包含数据,在模板中对它做任何处理几乎没什么用。但完全有理由用来渲染一张空表单——当我们希望用户来填充的时候就会这么做。

所以当我们在视图中处理模型实例时,我们一般从数据库中获取它。当我们处理表单时,我们一般在视图中实例化它。

当我们实例化一个表单时,我们可以选择将其保留为空,或者预先填充它,例如:

  • 来自已保存的模型实例的数据(例如在管理编辑表单的情况下)

  • 我们从其他来源获取的数据

  • 从前面一个HTML 表单提交过来的数据

最后一种情况最有趣,因为这使得用户不仅可以阅读网站,而且还可以将信息发回给它。

构建一张表单

需要完成的工作

假设您希望在您的网站上创建一张简易的表单,用来获取用户的名字。您需要在模板中使用类似代码:

<form action="/your-name/" method="post">
    <label for="your_name">Your name: label>
    <input id="your_name" type="text" name="your_name" value="{{ current_name }}">
    <input type="submit" value="OK">
form>

这告诉浏览器将表单数据返回给URL /your-name/ ,并使用 POST 方法。它将显示一个标签为 "Your name:" 的文本字段,以及一个 "OK" 按钮。如果模板上下文包含一个 current_name 变量,它会被预填充到 your_name 字段。

您需要一个视图来渲染这个包含HTML表单的模板,并能适当提供 current_name 字段。

提交表单时,发送给服务器的 POST 请求将包含表单数据。

现在,您还需要一个与该 /your-name/ URL相对应的视图,该视图将在请求中找到相应的键/值对,然后对其进行处理。

这是一个非常简单的表单。在实际应用中,一个表单可能包含几十个或数百个字段,其中许多字段可能需要预先填充,而且我们可能期望用户在完成操作之前多次执行编辑-提交周期。

我们可能需要在浏览器中进行一些验证,甚至在表单提交之前;我们可能希望使用更复杂的字段 ,以允许用户做类似日期选择等操作。

此刻,我们很容易通过使用Django来完成以上大部分工作。

在Django 中构建一张表单

Form

我们已经很清楚想要的HTML表单看起来会是什么样子。首先,在Django中这样做:

forms.py
from django import forms


class NameForm(forms.Form):
    your_name = forms.CharField(label="Your name", max_length=100)

它定义了一个只包含一个字段( your_name )的 Form 类。我们已经为这个字段提供了友好的标签,当它渲染后会显示在 中(在这种情况下,如果我们省略之前指定的 label ,它还是会自动生成一个一样的标签)。

字段的最大长度由 max_length 来定义。它做了两件事情。首先它在HTML的 上增加了 maxlength="100" (这样浏览器会在第一时间阻止用户输入超过这个数量的字符串)。其次它还会在Django收到浏览器传过来的表单时,对数据长度进行验证(也就是服务器端验证)。

A Form instance has an is_valid() method, which runs validation routines for all its fields. When this method is called, if all fields contain valid data, it will:

  • 返回 True

  • 将表单的数据放到它的属性 cleaned_data 中。

这样整个表单在第一次渲染时,会显示如下:

<label for="your_name">Your name: label>
<input id="your_name" type="text" name="your_name" maxlength="100" required>

注意它 没有 包含 标签和提交按钮。我们必须自己在模板中提供。

视图

发回Django网站的表单数据由视图来处理,一般和发布这个表单用的是同一个视图。这允许我们重用一些相同的逻辑。

为了处理表单,我们需要将它实例化到我们希望发布的URL的对应的视图中:

views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render

from .forms import NameForm


def get_name(request):
    # if this is a POST request we need to process the form data
    if request.method == "POST":
        # create a form instance and populate it with data from the request:
        form = NameForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required
            # ...
            # redirect to a new URL:
            return HttpResponseRedirect("/thanks/")

    # if a GET (or any other method) we'll create a blank form
    else:
        form = NameForm()

    return render(request, "name.html", {"form": form})

如果我们访问这个视图用的是 GET 请求,它会创建一个空的表单实例并将其放置在模板上下文中进行渲染。这是我们在首次访问这个URL时能预料到会发生的情况。

如果表单提交用的是 POST 请求,那么该视图将再次创建一个表单实例并使用请求中的数据填充它: form = NameForm(request.POST) 这叫“绑定数据到表单” (现在它是一张 绑定的 表单)。

我们调用表单的 is_valid() 方法;如果不为 True ,我们带着表单返回到模板。这次表单不再为空( 未绑定 ),所以HTML表单将用之前提交的数据进行填充,放到可以根据需要进行编辑和修正的位置。

如果 is_valid()True ,我们就能在其 cleaned_data 属性中找到所有通过验证的表单数据。我们可以在发送一个HTTP重定向告诉浏览器下一步去向之前用这些数据更新数据库或者做其他处理。

模板

我们没有必要在模板 name.html 中做过多的操作:

<form action="/your-name/" method="post">
    {% csrf_token %}
    {{ form }}
    <input type="submit" value="Submit">
form>

所有的表单字段及其属性都将通过Django模板语言从 {{ form }} 中被解包成HTML标记。

表格和跨站请求伪造保护

Django自带一个简单易用的 跨站请求伪造防护 。当通过 POST 方法提交一张启用了CSRF防护的表单时,您必须使用上例中这样的模板标签 csrf_token 。但是,由于CSRF防护在模板中没有与表单直接绑定,因此这个标签在本页文档之后的示例中都将被忽略。

HTML5输入类型和浏览器验证

如果您的表单包含 URLFieldEmailField 或者其他整数字段类型,Django 将使用 urlemailnumber HTML5 输入类型。默认情况下,浏览器可能会在这些字段上应用他们自己的验证,这也许比 Django 的验证更加严格。如果您想禁用这个行为,请在 form 标签上设置 novalidate 属性,或者在字段上指定一个不同的控件,比如 TextInput

现在我们有了一个可以工作的web表单,它通过一张Django Form 描述,由一个视图来处理并渲染成一个HTML

以上是您入门需要了解的所有内容,但是表单框架提供了更多垂手可得的内容。一旦您理解了上述过程的基础知识,您应该再了解下表单系统的其他功能,然后学习更多的底层机制。

详解Django Form

所有表单类都作为 django.forms.Form 或者 django.forms.ModelForm 的子类来创建。您可以把 ModelForm 想象成 Form 的子类。实际上 FormModelForm 从(私有) BaseForm 类继承了通用功能,但是这个实现细节不怎么重要。

模型和表单

实际上,如果您的表单是要直接用来添加或编辑Django模型,用 ModelForm ,可以省时、省力、省代码,因为它会根据 Model 类构建一张对应字段及其属性的表单。

绑定的和未绑定的表单实例

The distinction between 绑定和非绑定表单 is important:

  • 未绑定的表单没有与其关联的数据。当渲染给用户的时候,它会是空的或者包含默认值。

  • 绑定的表单拥有已提交的数据,因此可以用来判断数据是否合法。如果渲染了一张非法的绑定的表单,它将包含内联的错误信息,告知用户要纠正哪些数据。

表单的 is_bound 属性将告诉您一张表单是否具有绑定的数据。

字段详解

考虑一下比我们上面的小示例更有用的一张表单,我们可以用它在个人网站上实现“联系我”的功能:

forms.py
from django import forms


class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    message = forms.CharField(widget=forms.Textarea)
    sender = forms.EmailField()
    cc_myself = forms.BooleanField(required=False)

我们之前的表单只用了一个 CharField 类型的字段 your_name 。在这个例子中,我们的表单有四个字段: subjectmessagesendercc_myself 。只用到三种可用的字段类型: CharFieldEmailFieldBooleanField ;完整的字段类型清单请参看 表单字段

控件

每个表单字段都有一个相对应的 控件类 ,这个控件类又有对应的HTML表单控件,比如 type="text">

多数情况下,字段都有合适的默认控件。比如,默认情况下, CharField 有个 TextInput 控件,它会在HTML中生成一个 type="text"> 。如果您想要的是