Python 学习笔记

Django表单验证

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

简单的验证
我们的搜索示例仍然相当简单,特别是在数据验证方面。 我们只是检查,以确保搜索查询不是空的。 许多HTML表单都包含比确保值非空的验证级别更复杂的级别。 我们都看到了网站上的错误消息:

让我们调整我们的search()视图,以便验证搜索项长度小于或等于20个字符。 (为了举例,假设比这更长的话可能会使查询速度太慢)。我们该怎么做? 最简单的可能是将逻辑直接嵌入到视图中,如下所示:

def search(request):
    error = False
    if 'q' in request.GET:
        q = request.GET['q']
        if not q:
            error = True
        elif len(q) > 20:
            error = True
        else:
            books = Book.objects.filter(title__icontains=q)
            return render(request, 'search_results.html', {'books': books, 'query': q})
    return render(request, 'search_form.html', {'error': error})

现在,如果您尝试提交长度超过20个字符的搜索查询,则不会让您搜索; 你会得到一个错误消息。 但是search_form.html中的那个错误信息现在说“请提交一个搜索字词” - 所以我们必须改变它对于这两种情况的准确性:

<html>
<head>
    <title>Search</title>
</head>
<body>
    {% if error %}
        <p style="color: red;">
            Please submit a search term 20 characters or shorter.
        </p>
    {% endif %}

    <form action="/search/" method="get">
        <input type="text" name="q">
        <input type="submit" value="Search">
    </form>
</body>
</html>

这件事有一些丑陋的东西。 我们一刀切的错误信息可能会令人困惑。 为什么要提交一个空的表单提交的错误信息提到20个字符的限制? 错误消息应该是特定的,明确的而不是混淆的。 问题在于,我们使用简单的布尔值作为错误,而我们应该使用错误消息字符串列表。 以下是我们可以解决的问题:

def search(request):
    errors = []
    if 'q' in request.GET:
        q = request.GET['q']
        if not q:
            errors.append('Enter a search term.')
        elif len(q) > 20:
            errors.append('Please enter at most 20 characters.')
        else:
            books = Book.objects.filter(title__icontains=q)
            return render(request, 'search_results.html', {'books': books, 'query': q})
    return render(request, 'search_form.html', {'errors': errors})

然后,我们需要对search_form.html模板进行一些调整,以反映它现在传递了错误列表而不是错误布尔值:

<html>
<head>
    <title>Search</title>
</head>
<body>
    {% if errors %}
        <ul>
            {% for error in errors %}
            <li>{{ error }}</li>
            {% endfor %}
        </ul>
    {% endif %}
    <form action="/search/" method="get">
        <input type="text" name="q">
        <input type="submit" value="Search">
    </form>
</body>
</html>
制作联系表格

尽管我们多次对书籍搜索表单进行了迭代,并对其进行了很好的改进,但它仍然非常简单:只有一个字段'q'。随着表单变得越来越复杂,我们必须对我们使用的每个表单字段重复上述步骤。这引起了很多的烦恼和很多人为错误的机会。对我们来说幸运的是,Django的开发人员想到了这一点,并在Django中构建了一个更高级别的库,用于处理与表单验证相关的任务。

你的第一堂课

Django附带了一个名为django.forms的表单库,它处理我们一直在探索本章的许多问题 - 从HTML表单显示到验证。让我们深入并使用Django表单框架重写我们的联系表单应用程序。使用表单框架的主要方法是为每个正在处理的HTML <form>定义一个Form类。

在我们的例子中,我们只有一个<form>,所以我们将有一个Form类。 Django社区约定是将Form类保存在一个名为forms.py的单独文件中。在与mysite \ views.py相同的目录中创建该文件,然后输入以下内容:

# mysite_project\mysite\mysite\forms.py

from django import forms

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

这非常直观,与Django的模型语法相似。 表单中的每个字段都由一个Field类的类型表示 - CharField和EmailField是这里使用的唯一类型的字段 - 作为Form类的属性。 每个字段默认是必需的,所以为了使电子邮件可选,我们指定required = False。

让我们跳进Python交互式解释器,看看这个类可以做什么。 它能做的第一件事就是将自身显示为HTML:

(env_mysite) C:\Users\...\mysite> python manage.py shell

>>> from mysite.forms import ContactForm
>>> f = ContactForm()
>>> print(f)
<tr><th><label for="id_subject">Subject:</label></th><td><input type="text" name="subject" required id="id_subject" /></td></tr>
<tr><th><label for="id_email">Email:</label></th><td><input type="email" name="email" id="id_email" /></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" required id="id_message" /></td></tr>

Django为每个字段添加一个标签,以及用于访问的<label>标签。 这个想法是使默认行为尽可能最佳。 这个默认的输出格式是HTML <table>格式,但还有一些其他的内置输出:

>>> print(f.as_ul())
<li><label for="id_subject">Subject:</label> <input type="text" name="subject" required id="id_subject" /></li>
<li><label for="id_email">Email:</label> <input type="email" name="email" id="id_email" /></li>
<li><label for="id_message">Message:</label> <input type="text" name="message" required id="id_message" /></li>

>>> print(f.as_p())
<p><label for="id_subject">Subject:</label> <input type="text" name="subject" required id="id_subject" /></p>
<p><label for="id_email">Email:</label> <input type="email" name="email" id="id_email" /></p>
<p><label for="id_message">Message:</label> <input type="text" name="message" required id="id_message" /></p>

请注意,打开和关闭的<table>,<ul>和<form>标记不包含在输出中,因此您可以根据需要添加任何额外的行和自定义。 这些方法只是显示整个表单的常见情况的捷径。 您还可以显示特定字段的HTML:

>>> print(f['subject'])
<input type="text" name="subject" required id="id_subject" />
>>> print f['message']
<input type="text" name="message" required id="id_message" />

Form对象可以做的第二件事是验证数据。 要验证数据,请创建一个新的Form对象并将其传递一个将字段名称映射到数据的数据字典:

>>> f = ContactForm({'subject': 'Hello', 'email': 'nige@example.com', 'message': 'Nice site!'})

一旦你关联了一个Form实例的数据,你已经创建了一个“bound”的形式:

>>> f.is_bound
True

调用任何绑定窗体上的is_valid()方法,以确定其数据是否有效。 我们已经为每个字段传递了一个有效的值,所以表单的整体是有效的:

>>> f.is_valid()
True

如果我们不通过电子邮件字段,它仍然有效,因为我们已经为该字段指定了required = False:

>>> f = ContactForm({'subject': 'Hello', 'message': 'Nice site!'})
>>> f.is_valid()
True 

但是,如果我们忽略了主题或消息,表单不再有效:

>>> f = ContactForm({'subject': 'Hello'})
>>> f.is_valid()
False
>>> f = ContactForm({'subject': 'Hello', 'message': ''})
>>> f.is_valid()
False 

您可以深入了解特定于字段的错误消息:

>>> f = ContactForm({'subject': 'Hello', 'message': ''})
>>> f['message'].errors
['This field is required.']
>>> f['subject'].errors
[]
>>> f['email'].errors
[]

每个绑定的Form实例都有一个errors属性,它提供了一个将字段名称映射到错误消息列表的字典:

>>> f = ContactForm({'subject': 'Hello', 'message': ''})
>>> f.errors
{'message'`: ['This field is required.']}

最后,对于已经发现数据有效的表单实例,可以使用一个“ cleaned_data”属性。 这是提交的数据字典,“清理”。 Django的表单框架不仅验证数据, 它通过将值转换为适当的Python类型来清除它:

>>> f = ContactForm({'subject': 'Hello', 'email': 'nige@example.com', 'message': 'Nice site!'})
>>> f.is_valid() 
True
>>> f.cleaned_data
{'subject': 'Hello', 'email': 'nige@example.com', 'message': 'Nice site!'}

我们的联系表单只处理被“清理”成字符串对象的字符串 - 但是如果我们要使用IntegerField或DateField,则表单框架将确保已清空的数据为给定的字段使用适当的Python整数或datetime.date对象。

上一篇下一篇

猜你喜欢

热点阅读