Python 学习笔记

将表格与视图绑定

2018-02-02  本文已影响4人  大爷的二舅

我们的联系表单对我们来说并不是什么好事,除非我们有一些方式向用户展示。 要做到这一点,我们需要先更新我们的mysite \ views.py:

# mysite_project\mysite\mysite\views.py

from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.shortcuts import render
import datetime
from mysite.forms import ContactForm    
from django.core.mail import send_mail, get_connection

# ...

def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            con = get_connection('django.core.mail.backends.console.EmailBackend')
            send_mail(
                cd['subject'],
                cd['message'],
                cd.get('email', 'noreply@example.com'),
                ['siteowner@example.com'],
                connection=con
            )
            return HttpResponseRedirect('/contact/thanks/')
    else:
        form = ContactForm()

    return render(request, 'contact_form.html', {'form': form})

我们已经将联系功能添加到我们的视图来处理表单提交。 在这个新功能中,我们:

请注意,我们不在视图中进行任何错误处理 - 这全部由表单类处理。 如果表单没有验证,Django会自动创建一个错误列表并将它们追加到响应中。

联系表单没有太多用处,没有办法将联系表单信息发送给网站所有者。 这样做的一个非常普遍的方式是发送电子邮件。 Django能够发送内置到核心的电子邮件。 电子邮件功能可以在django.core.mail模块中找到,我已经在我们修改过的views.py的顶部导入了这个模块。

我们使用send_mail()函数将电子邮件发送到一个虚拟的电子邮件地址。 您可以在Django文档中的send_mail()以及其他电子邮件函数和类中找到更多信息。

在开发中发送电子邮件

您会注意到我正在使用django.core.mail.get_connection()来检索到特定电子邮件后端名为“django.core.mail.backends.console.EmailBackend”的邮件连接。 这个后端在开发中特别有用,因为它不需要你在开发一个Django应用程序的时候设置一个电子邮件服务器。 console.EmailBackend将电子邮件输出发送到控制台。 提交表格后,您可以在终端窗口中查看。
还有其他的电子邮件后台用于测试 - firebased,locmem和dummy,它们将您的电子邮件发送到本地系统上的文件,将其保存在内存中的属性中,并分别发送到虚拟后端。
您可以在电子邮件后台下的Django文档中找到更多信息。

为了能够显示我们的联系表格,我们必须创建我们的联系表格(保存为mysite \ templates):

# mysite_project\mysite\templates\contact_form.html

<html>
<head>
    <title>Contact us</title>
</head>
<body>
    <h1>Contact us</h1>

    {% if form.errors %}
        <p style="color: red;">
            Please correct the error{{ form.errors|pluralize }} below.
        </p>
    {% endif %}

    <form action="" method="post" novalidate>
        <table>
            {{ form.as_table }}
        </table>
        {% csrf_token %}
        <input type="submit" value="Submit">
    </form>
</body>
</html>

由于我们正在创建一个POST表单(这可能会影响修改数据),所以我们需要担心跨站点请求伪造。 值得庆幸的是,您不必太担心,因为Django带有一个非常容易使用的系统来保护它。

简而言之,所有以内部URL为目标的POST表单都应使用{%csrf_token%}模板标记。 关于{%csrf_token%}的更多细节可以在第19章找到。

敏锐的读者也会注意到<form>标签中的novalidate属性。 在某些最新版本的浏览器(特别是Chrome)中使用HTML5时,浏览器会自动验证表单字段。 因为我们希望Django处理表单验证,所以novalidate属性告诉浏览器不要验证表单。

最后,我们需要更改我们的urls.py以在/ contact /中显示我们的联系表单:

 # ...
from mysite.views import hello, current_datetime, hours_ahead, contact

 urlpatterns = [
     # ...
     url(r'^contact/$', contact),
     url(r'^', include('books.urls')),
]
尝试在本地运行。 加载表单,填写任何一个字段(图6-5),提交一个无效的电子邮件地址(图6-6),最后提交有效的数据。 图6-5。 Django表单类提供了字段的自动验证。.png 图6-6。 Django也检查有效的电子邮件地址。.png

请注意,当您提交完整的表单时,您将收到“页面未找到(404)”错误。 这是因为我还没有创建重定向到/ contact / thanks /的视图或URLconf。 我会把这个留给你作为一个学习练习。

更改字段的呈现方式

当您在本地呈现此表单时,您可能会首先注意到消息字段显示为<input type =“text”>,并且应该是<textarea>。 我们可以通过设置字段的小部件来解决这个问题:

from django import forms

class ContactForm(forms.Form):
    subject = forms.CharField()
    email = forms.EmailField(required=False)
    message = forms.CharField(widget=forms.Textarea)

表单框架将每个字段的表示逻辑分隔成一组小部件。 每个字段类型都有一个默认的小部件,但是您可以轻松地覆盖默认的小部件,或者提供您自己的自定义小部件。 将Field类视为表示验证逻辑,而小部件表示表示逻辑。

设置最大长度

最常见的验证需求之一是检查字段是否具有一定的大小。 为了好的措施,我们应该改进我们的ContactForm,以限制主题为100个字符。 为此,只需向CharField提供一个max_length,如下所示:

from django import forms

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

一个可选的min_length参数也是可用的。

设置初始值

作为对这种形式的改进,我们为主题字段添加一个初始值:“我爱你的网站!”(建议的一点力量不能伤害。)为此,我们可以使用初始参数,当我们创建一个 表格实例:

def contact(request):
    
    # ...

    else:
        form = ContactForm(
            initial={'subject': 'I love your site!'}
        )
        
    return render(request, 'contact_form.html', {'form':form})

现在,主题字段将被预先填入该种类的语句。 请注意传递初始数据和绑定表单的传递数据之间是有区别的。 最大的区别是,如果您只是传递初始数据,那么表单将被解除绑定,这意味着它不会有任何错误消息。

图6-7展示了我们的窗体如何使用新的Textarea小部件来显示消息和预填充的主题行。 图6-7。 我们的Django表单中带有新的textarea小部件,用于消息和预先填充的主题字段。.png
自定义验证规则

想象一下,我们已经启动了我们的反馈表单,电子邮件已经开始滚滚而来。只有一个问题:提交的一些消息只是一两个单词,这些单词不够长,我们无法理解。 我们决定采用一个新的验证策略:请用四个字以上。

将自定义验证挂钩到Django表单中有很多种方法。 如果我们的规则是一次又一次的重用,我们可以创建一个自定义的字段类型。 大多数自定义验证是一次性事务,但可以直接绑定到Form类。 我们需要对消息字段进行额外的验证,所以我们在我们的Form类中添加一个clean_message()方法:

from django import forms

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

    def clean_message(self):
        message = self.cleaned_data['message']
        num_words = len(message.split())
        if num_words < 4:
            raise forms.ValidationError("Not enough words!")
        return message

Django的表单系统自动查找名称以clean_开头并以此字段名称结尾的任何方法。 如果存在任何这样的方法,则在验证期间被调用。 具体来说,clean_message()方法将在给定字段的默认验证逻辑(在这种情况下,为所需的CharField的验证逻辑)之后被调用。 由于现场数据已被部分处理,我们将其从self.cleaned_data中取出。

此外,我们不必担心检查值是否存在而且是非空的; 这是由默认的验证器完成的。 我们天真地使用len()和split()的组合来计算单词的数量。 如果用户输入了太少的话,我们引发一个forms.ValidationError。 附加到此异常的字符串将作为错误列表中的项显示给用户(图6-8)。 图6-8。 当输入少于4个字时,我们的消息字段的自定义验证器将显示并出错。.png

重要的是我们明确地返回该方法结束时的字段清理值。 这使我们可以在我们的自定义验证方法中修改该值(或将其转换为不同的Python类型)。 如果我们忘记了return语句,那么None将被返回,原始值将会丢失。

指定标签

默认情况下,Django的自动生成的表单HTML标签是通过用空格替换下划线并大写第一个字母来创建的 - 所以电子邮件字段的标签是“Email”。 (听起来很熟悉吗?Django的模型用于计算字段的默认verbose_name值是一样的简单算法,我们在第4章中已经介绍过)。但是,和Django的模型一样,我们可以为给定的字段定制标签。 只要使用label,就像这样:

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    email = forms.EmailField(required=False, label='Your e-mail address')
    message = forms.CharField(widget=forms.Textarea)

自定义表单设计
我们的contact_form.html模板使用{{form.as_table}}来显示表单,但是我们可以通过其他方式显示表单以获得更精确的显示控制。 定制表单演示的最快捷方式是使用CSS。 错误列表,特别是可以做一些视觉增强,自动生成的错误列表精确地使用<ul class =“errorlist”>,以便您可以使用CSS来定位它们。 在contact_form.html的<head> </ head>部分添加下面的CSS,让我们的错误更加突出(图6-9):

<style type="text/css">
    ul.errorlist {
        margin: 0;
        padding: 0;
    }
    .errorlist li {
        background-color: red;
        color: white;
        display: block;
        font-size: 1.2em;
        margin: 0 0 3px;
        padding: 4px 5px;
    }
</style>
图6-9。 添加样式到我们的错误列表.png

虽然为我们生成表单的HTML是很方便的,但在许多情况下,您会想要覆盖默认的呈现。 在开发应用程序时,{{form.as_table}}和朋友是有用的快捷方式,但是关于表单显示方式的所有内容都可以被覆盖,大部分都在模板本身内,而且您可能会发现自己正在执行此操作。

可以通过访问模板中的{{form.fieldname}}来单独呈现每个字段的小部件(<input type =“text”>,<select>,<textarea>等),并且可以使用与字段关联的任何错误 作为{{form.fieldname.errors}}。 考虑到这一点,我们可以使用以下模板代码为我们的联系表单构建一个自定义模板:

<html>
<head>
    <title>Contact us</title>
</head>
<body>
    <h1>Contact us</h1>

    {% if form.errors %}
        <p style="color: red;">
            Please correct the error{{ form.errors|pluralize }} below.
        </p>
    {% endif %}

    <form action="" method="post">
        <div class="field">
            {{ form.subject.errors }}
            <label for="id_subject">Subject:</label>
            {{ form.subject }}
        </div>
        <div class="field">
            {{ form.email.errors }}
            <label for="id_email">Your e-mail address:</label>
            {{ form.email }}
        </div>
        <div class="field">
            {{ form.message.errors }}
            <label for="id_message">Message:</label>
            {{ form.message }}
        </div>
        {% csrf_token %}
        <input type="submit" value="Submit">
    </form>
</body>
</html>

在上面的模板代码中,如果错误出现,{{form.message.errors}}将显示一个<ul class =“errorlist”>,如果该字段有效(或者表单未绑定),则显示一个空字符串。 我们的联系表格上的其他字段也是如此。

我们也可以将form.message.errors当作一个布尔值,或者甚至将它作为一个列表迭代。 当有一个字段可能有多个错误时,这很有用。 例如:

<div class="field{% if form.message.errors %} errors{% endif %}">
    {% if form.message.errors %}
        <ul>
        {% for error in form.message.errors %}
            <li><strong>{{ error }}</strong></li>
        {% endfor %}
        </ul>
    {% endif %}
    <label for="id_message">Message:</label>
    {{ form.message }}
</div>

在验证错误的情况下,这将为包含的<div>添加一个“errors”类,并在无序列表中显示与消息字段相关的错误列表。

下一步是什么?
本章总结了本书中的介绍性材料 - 所谓的“核心课程”。本书的下一部分(第7章至第13章)详细介绍了高级Django的用法,包括如何部署Django应用程序(第13章)。 在这七个章节之后,您应该足够了解开始编写自己的Django项目。 本书的其余内容将帮助您填写缺少的部分。 我们将在第7章开始,回顾一下并仔细研究视图和URLconf(在第2章中首先介绍)。

上一篇下一篇

猜你喜欢

热点阅读