在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
简介除非您打算建立只发布内容的网站和应用程序,并且不接受访问者的输入,否则您将需要理解和使用表格。 Django提供了一系列工具和库,可帮助您构建表单以接受来自站点访问者的输入,然后处理并响应输入。 HTML表单在HTML中,表单是内部元素的集合<form>...</form>,允许访问者执行诸如输入文本,选择选项,操作对象或控件等操作,然后将该信息发送回服务器。 其中一些表单界面元素(文本输入或复选框)内置于HTML本身。其他则要复杂得多。弹出日期选择器或允许您移动滑块或操纵控件的界面通常将使用JavaScript和CSS以及HTML表单<input>元素来实现这些效果。 <input>表单及其元素还必须指定两件事:
Django表单处理流程 Django 的表单处理:视图获取请求,执行所需的任何操作,包括从模型中读取数据,然后生成并返回HTML页面(从模板中),我们传递一个包含要显示的数据的上下文。使事情变得更复杂的是,服务器还需要能够处理用户提供的数据,并在出现任何错误时,重新显示页面。 Django表单处理的主要内容:
Django表单分为两种使用方法:
GET 方法
GET方法是通过键值对的方式显示从用户那边获取的数据,然后通过“&”将其组合形成一个整体的字符串,最后加上“?”,将组合后的字符串拼接到URL内,生成一个url地址。它既不适用于大量数据,也不适合于二进制数据(例如图像)。使用 POST 方法
POST可以更改系统状态的任何请求,利用POST方法,浏览器可以将表单数据进行打包操作,然后以编码的方式进行传输,最后将它发送到服务器,并接收对其进行响应。 Django在表单中的角色处理表格是一项复杂的业务。考虑一下Django的管理员,其中可能需要准备好几种不同类型的大量数据,以表格形式显示,呈现为HTML,使用便利的界面进行编辑,返回到服务器,进行验证和清理,然后保存或传递进行进一步处理。 Django的表单功能可以简化和自动化大部分工作,并且比大多数程序员在编写自己的代码中所能做到的更加安全。 Django处理涉及表单的工作的三个不同部分:
这是有可能到手动做这一切写代码,但Django的可以照顾这一切为您服务。 Django中的表单我们已经简要描述了HTML表单,但是HTML <form>只是所需机制的一部分。 在Web应用程序的上下文中,“表单”可能是指该HTML <form>或Form生成它的Django ,或者是提交时返回的结构化数据,或者是这些部分的端到端工作集合。 Django Form类该组件系统的核心是Django的Form类。类与Django模型描述对象的逻辑结构,其行为以及向我们表示其部分的方式几乎相同,一个 Form类描述一种形式并确定其工作方式和外观。 就像模型类的字段映射到数据库字段一样,表单类的字段映射到HTML表单<input>元素。(A 通过;ModelForm 将模型类的字段映射到HTML表单<input>元素 Form,这是Django管理员所基于的。) 表单的字段本身就是类。他们管理表单数据并在提交表单时执行验证。一个DateField和 FileField手柄非常不同类型的数据,并有做不同的事情吧。 表单字段在浏览器中以HTML“窗口小部件”的形式向用户表示-一种用户界面机制。每个字段类型都有一个适当的默认 Widget类,但是可以根据需要覆盖它们。 实例化,处理和呈现表单在Django中渲染对象时,通常:
在模板中呈现表单与呈现任何其他类型的对象几乎涉及相同的工作,但是存在一些关键区别。 对于不包含数据的模型实例,在模板中执行任何操作几乎是没有用的。另一方面,呈现未填充的表单非常有意义-当我们希望用户填充它时,这就是我们要做的。 因此,当我们在视图中处理模型实例时,通常会从数据库中检索它。当我们处理表单时,通常在视图中实例化它。 实例化表单时,我们可以选择将其保留为空或预先填充,例如:
这些情况中的最后一个是最有趣的,因为它使用户不仅可以阅读网站,而且还可以向其发送信息。 构建形式这方面还需要做需要的工作假设您想在您的网站上创建一个简单的表单,以获得用户名。您在模板中需要这样的内容: <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/使用POST方法将表单数据返回到URL 。它将显示一个文本字段,标记为“您的姓名:”,以及一个标记为“确定”的按钮。如果模板上下文包含一个current_name 变量,它将用于预填充该your_name字段。 您将需要一个视图来呈现包含HTML表单的模板,并且可以提供current_name适当的字段。 提交表单后,POST发送到服务器的请求将包含表单数据。 现在,您还将需要一个与该/your-name/URL 对应的视图,该视图将在请求中找到适当的键/值对,然后对其进行处理。 这是一个非常简单的形式。实际上,一个表单可能包含数十个或数百个字段,其中许多字段可能需要预先填充,并且我们可能希望用户在结束操作之前先完成几次编辑-提交循环。 甚至在提交表单之前,我们可能需要在浏览器中进行一些验证;我们可能想使用更复杂的字段,使用户可以执行诸如从日历中选择日期之类的操作。 在这一点上,让Django为我们完成大部分工作要容易得多。 在Django中建立表单本Form类我们已经知道我们想要HTML表单的外观了。我们在Django中的起点是: 的forms.py
这定义了一个Form具有单个字段(your_name)的类。我们在该字段上应用了一个人类友好的标签,该标签将在<label>呈现时显示在标签上(尽管在这种情况下,label 我们指定的标签实际上与省略该标签时会自动生成的标签 相同)。 字段的最大允许长度由定义 max_length。这有两件事。它放在 maxlength="100"HTML上<input>(因此浏览器应首先防止用户输入超过该数量的字符)。这也意味着,当Django从浏览器接收回表单时,它将验证数据的长度。 一个Form实例有一个is_valid()方法,它运行于所有的字段验证程序。调用此方法时,如果所有字段都包含有效数据,它将:
首次渲染时,整个表单将如下所示: <label for="your_name">Your name: </label> <input id="your_name" type="text" name="your_name" maxlength="100" required> 请注意,它不包含<form>标签或提交按钮。我们必须在模板中提供这些信息。 视图发送回Django网站的表单数据由视图处理,通常与发布表单的视图相同。这使我们可以重用某些相同的逻辑。 要处理表单,我们需要在视图中将其实例化的URL实例化为: 的views.pyfrom 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的模板语言从中解压缩为HTML标记。{{ form }} 表格和跨站点请求伪造保护 Django随附了易于使用的跨站点请求伪造保护。在POST启用CSRF保护的情况下提交表单时,必须csrf_token像前面的示例一样使用template标记。但是,由于CSRF保护并不直接与模板中的表单相关联,因此在本文档的以下示例中省略了此标签。 HTML5输入类型和浏览器验证 如果表单包括URLField,一个 EmailField或任何整数字段类型,Django会使用的url,email和numberHTML5输入类型。默认情况下,浏览器可以在这些字段上应用自己的验证,这可能比Django的验证更严格。如果您想禁用此行为,请novalidate在form标签上设置属性,或在字段上指定其他小部件,例如TextInput。 现在,我们有了一个工作的Web表单,该表单由Django描述Form,由视图处理并呈现为HTML <form>。 这就是您入门所需的全部内容,但是表单框架为您提供了更多便利。一旦了解了上述过程的基础,就应该准备了解表单系统的其他功能,并准备进一步了解基础机械。 有关Django Form类的更多信息所有表单类均作为django.forms.Form 或的子类创建django.forms.ModelForm。您可以将其ModelForm视为的子类Form。Form并ModelForm实际上从(私有)BaseForm类继承通用功能,但是这种实现细节很少很重要。 模型和形式 实际上,如果您的表单将用于直接添加或编辑Django模型,那么ModelForm可以节省大量的时间,精力和代码,因为它可以构建表单以及适当的字段及其属性,来自一Model堂课。 绑定表单实例和未绑定表单实例绑定形式和未绑定形式之间的区别很重要:
表单的is_bound属性将告诉您表单是否绑定了数据。 更多的字段考虑一个比上面的最小示例更有用的形式,我们可以使用该形式在个人网站上实现“与我联系”功能: 的forms.pyfrom 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) 我们之前的形式使用的单场,your_name,一CharField。在这种情况下,我们的表单有四个字段:subject,message,sender和 cc_myself。CharField,EmailField并且 BooleanField只有三个可用的字段类型; 完整列表可以在“ 表单”字段中找到。 小部件每个表单字段都有一个对应的Widget类,该类又对应于HTML表单小部件,例如。<input type="text"> 在大多数情况下,该字段将具有明智的默认小部件。例如,默认情况下,a CharField将具有在HTML TextInput中生成a的小部件。如果需要 ,可以在定义表单字段时指定适当的小部件,就像我们对字段所做的那样。<input type="text"><textarea>message 现场数据无论通过表单提交的数据是什么,一旦通过调用成功验证is_valid()(并is_valid()返回True),经过验证的表单数据都将位于form.cleaned_data字典中。这些数据将为您很好地转换为Python类型。 注意 此时,您仍然可以直接访问未经验证的数据request.POST,但是经过验证的数据更好。 在上面的联系表单示例中,cc_myself将为布尔值。同样,诸如IntegerField和FloatField将值分别转换为Python int和的字段float。 以下是在处理此表单的视图中如何处理表单数据的方法: 的views.pyfrom 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 = ['[email protected]'] if cc_myself: recipients.append(sender) send_mail(subject, message, sender, recipients) return HttpResponseRedirect('/thanks/') 小费 有关从Django发送电子邮件的更多信息,请参见发送电子邮件。 一些字段类型需要一些额外的处理。例如,使用表单上传的文件需要进行不同的处理(可以从而request.FILES不是从中检索它们 request.POST)。有关如何处理表单上载文件的详细信息,请参阅将上载的文件绑定到表单。 与表单模板工作将表单放入模板所需要做的就是将表单实例放入模板上下文中。因此,如果您的表单是form在上下文中调用的,则将适当地呈现其和元素。{{ form }}<label><input> 形成渲染选项附加表格模板家具 不要忘了,一个形式的输出并没有包括周围的 <form>标签,或窗体的submit控制。您必须自己提供这些。 <label>/ <input>对还有其他输出选项:
请注意,您必须自己提供周围环境<table>或<ul> 元素。 这是我们的实例的输出:{{ form.as_p }}ContactForm <p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></p> <p><label for="id_message">Message:</label> <textarea name="message" id="id_message" required></textarea></p> <p><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></p> <p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></p> 请注意,每个表单字段的ID属性设置为id_<field-name>,由随附的标签标记引用。这对于确保辅助技术(例如屏幕阅读器软件)可访问表单很重要。您还可以自定义标签和ID的生成方式。 有关更多信息,请参见将表单输出为HTML。 手动渲染领域我们不必让Django解压缩表单字段;我们可以根据需要手动进行操作(例如,允许我们对字段进行重新排序)。每个字段都可以使用用作表单的属性,并且在Django模板中将适当地呈现。例如:{{ form.name_of_field }} {{ 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> <label>也可以使用生成完整的元素 label_tag()。例如: <div class="fieldWrapper"> {{ form.subject.errors }} {{ form.subject.label_tag }} {{ form.subject }} </div> 呈现形式的错误消息当然,这种灵活性的代价是更多的工作。到目前为止,我们不必担心如何显示表单错误,因为这已经为我们解决了。在此示例中,我们必须确保处理每个字段的所有错误以及整个表单的所有错误。请注意在表单和模板查找的顶部,以查找每个字段上的错误。{{ form.non_field_errors }} 使用显示格式错误列表,并显示为无序列表。可能看起来像:{{ form.name_of_field.errors }} <ul class="errorlist"> <li>Sender is required.</li> </ul> 该列表的CSS类errorlist允许您设置外观样式。如果您希望进一步自定义错误的显示,可以通过遍历它们来实现: {% if form.subject.errors %} <ol> {% for error in form.subject.errors %} <li><strong>{{ error|escape }}</strong></li> {% endfor %} </ol> {% endif %} 非字段错误(和/或使用诸如的辅助工具时在表单顶部显示的隐藏字段错误form.as_p())将通过附加的类别呈现,nonfield以帮助将其与特定于字段的错误区分开。例如,如下所示:{{ form.non_field_errors }} <ul class="errorlist nonfield"> <li>Generic validation error</li> </ul> 有关错误,样式以及如何在模板中使用表单属性的更多信息,请参见Forms API。 遍历表单的字段如果您对每个表单字段使用相同的HTML,则可以通过使用 循环依次遍历每个字段来减少重复代码:{% for %} {% for field in form %} <div class="fieldWrapper"> {{ field.errors }} {{ field.label_tag }} {{ field }} {% if field.help_text %} <p class="help">{{ field.help_text|safe }}</p> {% endif %} </div> {% endfor %} 有用的属性包括:{{ field }}
{% if field.is_hidden %} {# Do something special #} {% endif %}
也可以看看 有关属性和方法的完整列表,请参见 BoundField。 遍历隐藏和可见字段如果您要手动在模板中布置表单,而不是依赖Django的默认表单布局,则可能需要将 字段与非隐藏字段区别对待。例如,由于隐藏字段不显示任何内容,因此将错误消息放在该字段旁边可能会给您的用户造成混乱-因此,应对这些字段的错误进行不同的处理。<input type="hidden"> Django在表单上提供了两种方法,可让您独立遍历隐藏字段和可见字段:hidden_fields()和 visible_fields()。这是对使用这两种方法的先前示例的修改: {# Include the hidden fields #} {% for hidden in form.hidden_fields %} {{ hidden }} {% endfor %} {# Include the visible fields #} {% 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: {% include "form_snippet.html" with form=comment_form %} 如果您发现自己经常这样做,则可以考虑创建一个自定义 包含标签。 详情参考: https://docs.djangoproject.com/en/3.0/topics/forms/#working-with-form-templates |
请发表评论