阅读(2522) (0)

Django4.0 使用表单-构建一张表单

2022-03-16 11:42:50 更新

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

<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来完成以上大部分工作。

Form类

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

from django import forms

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

它定义了一个只包含一个字段( ​your_name ​)的 ​Form ​类。我们已经为这个字段提供了友好的标签,当它渲染后会显示在 ​<label>​ 中(在这种情况下,如果我们省略之前指定的 label ,它还是会自动生成一个一样的标签)。
字段的最大长度由 ​max_length ​来定义。它做了两件事情。首先它在HTML的 ​<input>​ 上增加了 ​maxlength="100"​ (这样浏览器会在第一时间阻止用户输入超过这个数量的字符串)。其次它还会在Django收到浏览器传过来的表单时,对数据长度进行验证(也就是服务器端验证)。

Form 实例有一个 ​is_valid()​ 方法,该方法对其所有字段运行验证例程。 调用此方法时,如果所有字段都包含有效数据,它将:

  • 返回 ​True
  • 将表单的数据放到它的属性 ​cleaned_data ​中

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

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

视图

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

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

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输入类型和浏览器验证

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

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