<form>...</form> 之间元素的集合,它们允许访问者输入文本、选择选项、操作对象和控制等等,然后将信息发送回服务器。

<input> 元素来实现操作控制的界面。

<input> 元素一样,一个表单必须指定两样东西:

  • 目的地:响应用户输入数据的URL
  • 方式:发送数据所使用的HTTP 方法

它还包含一些用户看不到的隐藏的文本字段,Django 使用它们来决定下一步的行为。

post

/admin/


POST 方法。

POST 方法,在这个方法中浏览器组合表单数据、对它们进行编码以用于传输、将它们发送到服务器然后接收它的响应。

https://docs.djangoproject.com/search/?q=forms&release=1 形式的URL。

POST 用于不同的目的。

GET 只应该用于不会影响系统状态的请求。

CSRF 保护。

GET 请求的URL 可以很容易地作为书签、分享和重新提交。


考虑一下Django 的Admin 站点,不同类型的大量数据项需要在一个表单中准备好、渲染成HTML、使用一个方便的界面编辑、返回给服务器、验证并清除,然后保存或者向后继续处理。

Django 的表单功能可以简化并自动化大部分这些工作,而且还可以比大部分程序员自己所编写的代码更安全。

Django 会处理表单工作中的三个显著不同的部分:

  • 准备数据、重构数据,以便下一步提交。
  • 为数据创建HTML 表单
  • 接收并处理客户端提交的表单和数据

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


<form> 只是其机制的一部分。

Form、或者提交时发送的结构化数据、或者这些部分的总和。


Form 类描述一个表单并决定它如何工作和展现。

<input> 元素;Django 的Admin 站点就是基于这个)。

FileField 处理的数据类型差别很大,必须完成不同的事情。

Widget 类,需要时可以覆盖。


在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>

your_name 字段。

current_name 字段。

POST 请求将包含表单数据。

/your-name/ URL 的视图,它在请求中找到正确的键/值对,然后处理它们。

实际应用中,一个表单可能包含几十上百个字段,其中大部分需要预填充,而且我们预料到用户将来回编辑-提交几次才能完成操作。

我们可能想使用非常复杂的字段,以允许用户做类似从日历中挑选日期这样的事情,等等。

这个时候,让Django 来为我们完成大部分工作是很容易的。



在Django 中,我们的起始点是这里:

forms.py
from django import forms

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

label还是会自动生成)。

它还意味着当Django 收到浏览器发送过来的表单时,它将验证数据的长度。

当调用这个方法时,如果所有的字段都包含合法的数据,它将:

  • True
  • cleaned_data 属性中。

完整的表单,第一次渲染时,看上去将像:

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

我们必须自己在模板中提供它们。


这允许我们重用一些相同的逻辑。

要操作一个通过URL发布的表单,我们要在视图中实例表单。

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

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})

这是我们在第一次访问该URL 时预期发生的情况。

这叫做”绑定数据至表单“(它现在是一个绑定的表单)。

这时表单不再为空(未绑定),所以HTML 表单将用之前提交的数据填充,然后可以根据要求编辑并改正它。

在发送HTTP 重定向给浏览器告诉它下一步的去向之前,我们可以用这个数据来更新数据库或者做其它处理。


最简单的例子是:

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

}},所有的表单字段和它们的属性将通过Django 的模板语言拆分成HTML 标记 。

表单和跨站请求伪造的防护

然而,因为CSRF 防护在模板中不是与表单直接捆绑在一起的,这个标签在这篇文档的以下示例中将省略。

HTML5 输入类型和浏览器验证

TextInput

<form>

一旦你理解了上面描述的基本处理过程,你应该可以理解表单系统的其它功能并准备好学习更多的底层机制。


ModelForm。

模型和表单

Model 类构建一个表单以及适当的字段和属性。 


绑定的和未绑定的表单 之间的区别非常重要:

  • 当渲染给用户时,它将为空或包含默认的值。
  • 如果渲染一个不合法的绑定的表单,它将包含内联的错误信息,告诉用户如何纠正数据。

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


考虑一个比上面的迷你示例更有用的一个表单,我们可以用它来在一个个人网站上实现“contact me”功能:

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)

表单字段中找到。


message字段。

这些数据已经为你转换好为Python 的类型。

request.POST 中直接访问到未验证的数据,但是访问验证后的数据更好一些。

float

下面是在视图中如何处理表单数据:

views.py
from django.core.mail import send_mail

if form.is_valid():
    subject = form.cleaned_data['subject']
    message = form.cleaned_data['message']
    sender = form.cleaned_data['sender']
    cc_myself = form.cleaned_data['cc_myself']

    recipients = ['info@example.com']
    if cc_myself:
        recipients.append(sender)

    send_mail(subject, message, sender, recipients)
    return HttpResponseRedirect('/thanks/')

提示

发送邮件。

绑定上传的文件到一个表单。


<input>元素。


表单模板的额外标签

你必须自己提供它们。

<input> 对,还有几个输出选项:

  • <tr> 标签中
  • <p> 标签中
  • <li> 标签中

<ul> 元素。

}}

<p><label for="id_subject">Subject:</label>
    <input id="id_subject" type="text" name="subject" maxlength="100" /></p>
<p><label for="id_message">Message:</label>
    <input type="text" name="message" id="id_message" /></p>
<p><label for="id_sender">Sender:</label>
    <input type="email" name="sender" id="id_sender" /></p>
<p><label for="id_cc_myself">Cc myself:</label>
    <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>

自定义label 和 id 生成的方式。

输出表单为HTML。


例如:

{{ form.non_field_errors }}
<div class="fieldWrapper">
    {{ form.subject.errors }}
    <label for="{{ form.subject.id_for_label }}">Email subject:</label>
    {{ form.subject }}
</div>
<div class="fieldWrapper">
    {{ form.message.errors }}
    <label for="{{ form.message.id_for_label }}">Your message:</label>
    {{ form.message }}
</div>
<div class="fieldWrapper">
    {{ form.sender.errors }}
    <label for="{{ form.sender.id_for_label }}">Your email address:</label>
    {{ form.sender }}
</div>
<div class="fieldWrapper">
    {{ form.cc_myself.errors }}
    <label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label>
    {{ form.cc_myself }}
</div>

例如:

<div class="fieldWrapper">
    {{ form.subject.errors }}
    {{ form.subject.label_tag }}
    {{ form.subject }}
</div>


}} 查找每个字段的错误。

看上去可能像:

<ul class="errorlist">
    <li>Sender is required.</li>
</ul>

如果你希望进一步自定义错误信息的显示,你可以迭代它们来实现:

{% if form.subject.errors %}
    <ol>
    {% for error in form.subject.errors %}
        <li><strong>{{ error|escape }}</strong></li>
    {% endfor %}
    </ol>
{% endif %}

}} 看上去会像:

<ul class="errorlist nonfield">
    <li>Generic validation error</li>
</ul>
Changed in Django 1.8:

nonfield CSS 类型。

Forms API 以获得关于错误、样式以及在模板中使用表单属性的更多内容。


%} 循环迭代每个字段来减少重复的代码:

{% for field in form %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
    </div>
{% endfor %}

}} 中有用的属性包括:

{{ field.label }}
address
{{ field.label_tag }}

label_suffix 是一个冒号:

<label for="id_email">Email address:</label>
{{ field.id_for_label }}
如果你有一些内嵌的JavaScript 并且想避免硬编码字段的ID,这也是有用的。
{{ field.value }}
someone@example.com
{{ field.html_name }}
它将考虑到表单的前缀。
{{ field.help_text }}
与该字段关联的帮助文档。
{{ field.errors }}
这种情况下,循环中的每个对象只是一个包含错误信息的简单字符串。
{{ field.is_hidden }}
作为模板变量,它不是很有用处,但是可以用于条件测试,例如:
{% if field.is_hidden %}
   
{% endif %}
{{ field.field }}
%}


例如,因为隐藏的字段不会显示,在该字段旁边放置错误信息可能让你的用户感到困惑 —— 所以这些字段的错误应该有区别地来处理。

下面是使用这两个方法对前面一个例子的修改:


{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}

{% for field in form.visible_fields %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
    </div>
{% endfor %}

然而,你也可以很容易地为这些表单错误插入一些错误信息显示出来。


include 标签来重用它:

# In your form template:
{% include "form_snippet.html" %}

# In form_snippet.html:
{% for field in form %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
    </div>
{% endfor %}

with 参数来对它起个别名:

{% include "form_snippet.html" with form=comment_form %}

inclusion 标签。

相关文章:

  • 2021-11-02
  • 2021-10-25
  • 2021-07-29
  • 2018-06-12
  • 2021-10-25
猜你喜欢
  • 2021-11-03
  • 2021-06-02
  • 2021-09-09
  • 2021-11-12
  • 2021-08-23
  • 2021-06-27
相关资源
相似解决方案