Django表单验证

作者: 大爷的二舅 | 来源:发表于2018-02-01 22:59 被阅读4次

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

    • “请输入有效的电子邮件地址。 'foo'不是电子邮件地址。“
    • “请输入有效的五位美国邮政编码。 '123'不是邮政编码。“
    • “请输入YYYY-MM-DD格式的有效日期。”
    • “请输入至少8个字符的密码,并至少包含一个数字。”

    让我们调整我们的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对象。

    相关文章

      网友评论

        本文标题:Django表单验证

        本文链接:https://www.haomeiwen.com/subject/fqnjzxtx.html