Django 的 form类

Django 在表单中的角色

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

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

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

准备数据、重构数据,以便下一步提交。
为数据创建HTML 表单
接收并处理客户端提交的表单和数据
可以手工编写代码来实现,但是Django 可以帮你完成所有这些工作。

在Django 中构建一个表单

Form 类

我们已经计划好了我们的 HTML 表单应该呈现的样子。在Django 中,我们的起始点是这里:

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

它定义一个Form 类,只带有一个字段(your_name)。我们已经对这个字段使用一个友好的标签,当渲染时它将出现在

字段允许的最大长度通过max_length 定义。它完成两件事情。首先,它在HTML 的 上放置一个maxlength=”100” (这样浏览器将在第一时间阻止用户输入多于这个数目的字符)。它还意味着当Django 收到浏览器发送过来的表单时,它将验证数据的长度。

Form 的实例具有一个is_valid() 方法,它为所有的字段运行验证的程序。当调用这个方法时,如果所有的字段都包含合法的数据,它将:

返回True
将表单的数据放到cleaned_data 属性中。
完整的表单,第一次渲染时,看上去将像:

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

注意它不包含 标签和提交按钮。我们必须自己在模板中提供它们。

视图

发送给Django 网站的表单数据通过一个视图处理,一般和发布这个表单的是同一个视图。这允许我们重用一些相同的逻辑。

要操作一个通过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})

如果访问视图的是一个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>

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

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

Django 原生支持一个简单易用的跨站请求伪造的防护。当提交一个启用CSRF 防护的POST 表单时,你必须使用上面例子中的csrf_token 模板标签。然而,因为CSRF 防护在模板中不是与表单直接捆绑在一起的,这个标签在这篇文档的以下示例中将省略。

HTML5 输入类型和浏览器验证

如果你的表单包含URLField、EmailField 或其它整数字段类型,Django 将使用url、email和 number 这样的HTML5 输入类型。默认情况下,浏览器可能会对这些字段进行它们自身的验证,这些验证可能比Django 的验证更严格。如果你想禁用这个行为,请设置form 标签的novalidate 属性,或者指定一个不同的字段,如TextInput。

现在我们有了一个可以工作的网页表单,它通过Django Form 描述、通过视图处理并渲染成一个HTML 。

这是你入门所需要知道的所有内容,但是表单框架为了便利提供了更多的内容。一旦你理解了上面描述的基本处理过程,你应该可以理解表单系统的其它功能并准备好学习更多的底层机制。

拓展应用

required:是否可以为空。required=True 不可以为空,required=False 可以为空
max_length=4 最多4个值,超过不会显示
min_length=2 至少两个值,少于两个会返回提示信息
error_messages={‘required’: ‘邮箱不能为空’, ‘invalid’: ‘邮箱格式错误’} 自定义错误信息,invalid 是格式错误
widget=forms.TextInput(attrs={‘class’: ‘c1’}) 给自动生成的input标签自定义class属性
widget=forms.Textarea() 生成Textarea标签。widget默认生成input标签

实战

models.py

from django.db import models
class Author(models.Model):
    """
    作者
    """
    name = models.CharField(max_length=100)
    age = models.IntegerField()

class BookType(models.Model):
    """
    图书类型
    """
    caption = models.CharField(max_length=64)

class Book(models.Model):
    """
    图书
    """
    name = models.CharField(max_length=64)
    pages = models.IntegerField()
    price = models.DecimalField(max_digits=10,decimal_places=2)
    pubdate = models.DateField()
    authors = models.ManyToManyField(Author)
    book_type = models.ForeignKey(BookType)

forms.py:

from django import forms
from app01 import models

class Form1(forms.Form):
    user = forms.CharField(label='Your name',
        widget=forms.TextInput(attrs={'class': 'c1'}),
        error_messages={'required': '用户名不能为空'}, )

    pwd = forms.CharField(max_length=4, min_length=2, required=True,
         error_messages = {'required': '密码不能为空'}
                          )
    email = forms.EmailField(error_messages={'required': '邮箱不能为空', 'invalid': '邮箱格式错误'})

    memo = forms.CharField(
        widget=forms.Textarea(),error_messages={'required': 'memo不能为空'}
    )
    vip_type = (
        (0, u'普通用户'),
        (1, u'高级用户'),)
    vip = forms.CharField(widget=forms.widgets.Select(choices=vip_type, attrs={'class': 'form-control'}))




    #写上以下代码就不用担心数据库添加了数据而不能及时获取了
    def __init__(self, *args, **kwargs):
        #每次创建Form1对象时执行init方法
        super(Form1, self).__init__(*args, **kwargs)

        self.fields['book_type'] = forms.CharField(
            widget=forms.widgets.Select(choices=models.BookType.objects.values_list('id', 'caption'),
                                        attrs={'class': "form-control"}))
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .input-group{
            position: relative;
            padding: 20px;
            width: 250px;
        }
        .input-group input{
            width: 200px;
            display: inline-block;
        }
        .inline-group span{
            display: inline-block;
            position: absolute;
            height: 12px;
            font-size: 8px;
            border: 1px solid red;
            background-color: coral;
            color: white;
            top: 41px;
            left: 20px;
            width: 202px;
        }
    </style>
</head>
<body>
    <form action="/form1/" method="POST">
        {% csrf_token %}
<div class="input-group">
<label>用户名:</label>{{ form.user }}<span>{{ form.user.errors }}</span>
</div>

<div class="input-group">
<label>密码:</label>{{ form.pwd }}<span>{{ form.pwd.errors }}</span>
</div>

<div class="input-group">
<label>邮箱:</label>{{ form.email }}<span>{{ form.email.errors }}</span>
</div>

<div class="input-group">
<label>memo:</label>{{ form.memo }}<span>{{ form.memo.errors }}</span>
</div>
<div class="input-group">
<label>会员等级:</label>{{ form.vip }}<span>{{ form.vip.errors }}</span>
</div>
<div>
    <input type="submit" value="提交" />
</div>
    </form>

</body>
</html>

views.py

from django.shortcuts import render,HttpResponse
from app01.forms import Form1
from app01.models import *

def form1(request):
    if request.method == "POST":
        f = Form1(request.POST)
        if f.is_valid():
            print(f.cleaned_data)
        else:
            return render(request,"account/form1.html",{"error":f.errors,"form":f})
    else:
        # 如果不是post提交数据,就不传参数创建对象,并将对象返回给前台,直接生成input标签,内容为空
        f = Form1()
        return render(request,"account/form1.html",{"form":f})
    return render(request,"account/form1.html")

Django里面没有手机验证,没有的需要自定义

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
from django import forms
from django.core.exceptions import ValidationError


def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('手机号码格式错误')


class PublishForm(forms.Form):

    user_type_choice = (
        (0, u'普通用户'),
        (1, u'高级用户'),
    )

    user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
                                                                  attrs={'class': "form-control"}))

    title = forms.CharField(max_length=20,
                            min_length=5,
                            error_messages={'required': u'标题不能为空',
                                            'min_length': u'标题最少为5个字符',
                                            'max_length': u'标题最多为20个字符'},
                            widget=forms.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'标题5-20个字符'}))

    memo = forms.CharField(required=False,
                           max_length=256,
                           widget=forms.widgets.Textarea(attrs={'class': "form-control no-radius", 'placeholder': u'详细描述', 'rows': 3}))

    phone = forms.CharField(validators=[mobile_validate, ],
                            error_messages={'required': u'手机不能为空'},
                            widget=forms.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'手机号码'}))

    email = forms.EmailField(required=False,
                            error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
                            widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))

    def publish(request):
    ret = {'status': False, 'data': '', 'error': '', 'summary': ''}
    if request.method == 'POST':
        request_form = PublishForm(request.POST)
        if request_form.is_valid():
            request_dict = request_form.clean()
            print request_dict
            ret['status'] = True
        else:
            error_msg = request_form.errors.as_json()
            ret['error'] = json.loads(error_msg)
    return HttpResponse(json.dumps(ret))

猜你喜欢

转载自blog.csdn.net/rorntuck7/article/details/77569805