Django 的 form类

来源:互联网 发布:plsql执行sql文件 编辑:程序博客网 时间:2024/05/21 09:37

Django 在表单中的角色

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

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

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

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

在Django 中构建一个表单

Form 类

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

forms.pyfrom django import formsclass 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 renderfrom django.http import HttpResponseRedirectfrom .forms import NameFormdef 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 modelsclass 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 formsfrom app01 import modelsclass 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,HttpResponsefrom app01.forms import Form1from 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 refrom django import formsfrom django.core.exceptions import ValidationErrordef 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))
原创粉丝点击