一 Form

    在实际的生产环境中,登录和注册时用户提交的数据浏览器端都会使用JavaScript来进行验证(比如验证输入是否为空以及输入是否合法),但是浏览器可能会禁用JavaScirpt,同时也有人可能会搞注入攻击,这样浏览器端的验证就无法发挥作用(一般不会禁用),所以在实际项目中一般都会进行两层验证,即客户端(浏览器)的验证和服务器端的验证。Django中的Form表单功能之一就是用来在服务器端对用户提交的数据做验证;它的另外一个功能是生成HTML标签。

   假如没有Django的Form表单,那么我们应该这么做

#/usr/bin/env python
#-*- coding:utf-8 -*-

from django.shortcuts import render

# Create your views here.
# 获取用户的相关信息
def user_list(request):
    host = request.POST.get('host')
    port = request.POST.get('port')
    mail = request.POST.get('mail')
    mobile = request.POST.get('mobile')
    
    # 在这里,存在两个问题
    # 1、从用户提交的数据中获取具体字段的信息时,我们要不停得get相关信息,如果字段很多,显然过于繁琐
    # 2、获取的数据,我们要自己进行合法性的验证或特定格式的验证,显然也很麻烦

    return render(request,'user_list.html')

       Django中Form的作用:(1)生成HTML标签;(2)用户提交数据验证

  1 生成HTML标签

   views.py文件

#!/usr/bin/env python
#-*- coding:utf-8 -*-

from django import forms,render
# 用户信息Form表单类,继承自forms.Form
class UserInfo(forms.Form):
     email = forms.EmailField(required=True) #required=True,表示内容不能为空
     host = forms.CharField() #默认requried=False,表示内容可以为空
     port = forms.CharField()
     mobile = forms.CharField()

# 定义函数,参数为request
def user_list(request):
    obj = UserInfo() #创建对象obj
    return render(request,'user_list.html',{'obj':obj})#把对象obj传给html

  user_list.html文件

<form action="/user_list/" method="post">
    <p>主机:{{ obj.host }}</p>
    <p>端口:{{ obj.port }}</p>
    <p>邮箱:{{ obj.email }}</p>
    <p>手机:{{ obj.mobile }}</p>
    <input type="submit" value="submit"/>
</form>

  2 简单的Form表单验证

   views.py文件

#!/usr/bin/env python
#-*- coding:utf-8 -*-

from django import forms,render

class UserInfo(forms.Form):
     email = forms.EmailField(required=False) #required是否可以为空,如果为False说明可以为空
     host = forms.CharField() #如果required不写,默认为Ture
     port = forms.CharField()
     mobile = forms.CharField()

def user_list(request):
    obj = UserInfo() #创建对象
    if request.method == 'POST':
        #获取用户输入,用户post的数据作为参数传递给UserInfo这个自定义的表单类,生成相应的对象后就可以做验证了
        user_input_obj = UserInfo(request.POST)
        #判断用户输入是否合法
        if user_input_obj.is_valid():
            #获取用户输入,这里获取的数据类型为字典
            data = user_input_obj.clean()
        # 如果不合法
        else:
            #捕捉错误信息
            error_msg = user_input_obj.errors
            print type(error_msg)
            '''
            <ul class="errorlist">
               <li>mobile
                 <ul class="errorlist">
                   <li>This field is required.</li>
                 </ul>
               </li>
               <li>host
                 <ul class="errorlist">
                   <li>This field is required.</li>
                 </ul>
               </li>
               <li>port
                 <ul class="errorlist">
                   <li>This field is required.</li>
                 </ul>
               </li>
            </ul>
            '''
            #然后把错误信息返回
            return render(request,'user_list.html',{'obj':obj,'errors':error_msg,})
    return render(request,'user_list.html',{'obj':obj,})

   user_list.html文件

<form action="/user_list/" method="post">
    <p>主机:{{ obj.host }}<span>{{ errors.host }}</span></p>
    <p>端口:{{ obj.port }}<span>{{ errors.port }}</span></p>
    <p>邮箱:{{ obj.email }}<span>{{ errors.email }}</span></p>
    <p>手机:{{ obj.mobile }}<span>{{ errors.mobile }}</span></p>
    <input type="submit" value="submit"/>
</form>

 效果图:

  3 自定义Form表单验证

  app01下forms模块中的account.py文件

#!/usr/bin/env python
#-*- coding:utf-8 -*-

from django import forms
from django.core.exceptions import ValidationError
import re

#自定义手机号码验证方法
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 LoginForm(forms.Form):
    user_type_choice = (
        (1,'普通用户'),
        (2,'超级用户'),
    )
    # 生成select标签,并且添加相应的属性
    user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,attrs={'class':'r'}))
    # 参数required可以省略,默认required=True,表示不能为空
    username = forms.CharField(required=True,error_messages={'required':u'用户名不能为空'})
    password = forms.CharField(required=True,error_messages={'required':u'密码不能为空'})
    mobile = forms.CharField(validators=[mobile_validate,], #应用自定义的验证方法
                             error_messages={'required':u'手机号码不能为空'},
# 生成提示信息,并且添加相应的属性 widget
=forms.TextInput(attrs={'class':'r','placeholder':u'手机号码'}) ) email = forms.EmailField(error_messages={'required':u'邮箱不能为空'}, # 生成提示信息,并且添加相应的属性,其中class=r是自定义的属性 widget=forms.TextInput(attrs={'class':'r','placeholder':u'邮箱'}) ) # 新增一个 memo = forms.CharField(required=False, widget=forms.Textarea(attrs={'class':'r','placeholder':'备注'}) )

  app01下views模块中的account.py文件

#!/usr/bin/env python
#-*- coding:utf-8 -*-

from django.shortcuts import render,HttpResponse
from app01.forms import account as AccountForm

def login(request):
    obj = AccountForm.LoginForm() # 生成Form对象
    if request.method == 'POST':
        user_input_obj = AccountForm.LoginForm(request.POST)  # 把提交的数据封装到Form对象中
        # 判断数据是否合法
        if user_input_obj.is_valid():
          # 获取提交的数据
            data = user_input_obj.clean()
        # 如果数据不合法
        else:
            error = user_input_obj.errors.as_data()
            # 注意下面变量的类型
            print type(error)   # <type 'dict'>

            print error['username'] # [ValidationError([u'\u7528\u6237\u540d\u4e0d\u80fd\u4e3a\u7a7a'])]
            print type(error['username']) # <type 'list'>

            print error['username'][0]  #[u'\u7528\u6237\u540d\u4e0d\u80fd\u4e3a\u7a7a']
            print type(error['username'][0]) #<class 'django.core.exceptions.ValidationError'>

            print error['username'][0][0] #用户名不能为空
            print type(error['username'][0][0]) #<type 'unicode'>

            return render(request,'account/login.html',{'obj':obj,'error':error})
    return render(request,'account/login.html',{'obj':obj})
#默认是as_ul(),即显示为ul的样式;如果写成as_data(),返回的是一个原生的字符串;as_json()与as_data()一样,
#也是返回的原生字符串 error_msg = user_input_obj.errors.as_data()

   app01下的templatetags模块中的xx.py文件(因为模板语言不支持用索引的方式取值,所以我们通过自定义simp_tag来进行取值)

#!/usr/bin/env python
#-*- coding:utf-8 -*-

from django import template
from django.utils.safestring import mark_safe
from django.template.base import resolve_variable, Node, TemplateSyntaxError

register = template.Library()

@register.simple_tag
def error_msg(arg):
    # 注意这里要做判断
    if arg:
        return arg[0][0]
    # 这里的返回空字符串也是必须的,否则报错
    return ''

   templates/account目录下的login.html文件

{% load xx %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/css/common.css"/>
</head>
<body>
    <form action="/login/" method="post">
        <p>
            用户主机类型: {{ obj.user_type }}
        </p>

        <p>
            姓名: {{ obj.username }}
           {#默认错误信息提示#}
           {#<span> {{ error.username }}</span>#}
           {#自定义错误信息提示#}
            <span> {% error_msg error.username %}</span>
        </p>
        <p>
            密码: {{ obj.password }}
            {#<span> {{ error.password }}</span>#}
            <span> {% error_msg error.password %}</span>
        </p>
        <p>
            手机号码: {{ obj.mobile }}
            {#<span> {{ error.mobile }}</span>#}
            <span> {% error_msg error.mobile %}</span>
        </p>
        <p>
            邮箱: {{ obj.email }}
            {#<span> {{ error.email }}</span>#}
            <span> {% error_msg error.email %}</span>
        </p>
        <p>
            备注: {{ obj.memo }}
        </p>

        <input type="submit" value="提交"/>

    </form>

</body>
</html>

 二 Ajax

    Django中怎么把前端数据在不刷新前端页面的前提下提交到后台,这里涉及到Django中Ajax提交数据到后台的问题。主要包括:(1)利用Ajax把前端简单数据(单条)提交到后台;(2)利用Ajax把前端复杂数据(多条)提交到后台。

 1 提交单条数据

   html页面,注意其中的注释

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Ajax提交数据</title>
</head>
<body>
    <form action="/user_list/" method="post">
       {# 提交数据button #}
        <input type="button" onclick="Ajaxsubmit();" value="Ajax提交"/>
        <table>
            <thead>
                <tr>
                    <th>主机名</th>
                    <th>端口</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>1.1.1.1</td>
                    <td>80000</td>
                </tr>
                <tr>
                    <td>1.1.1.1</td>
                    <td>80000</td>
                </tr>
            </tbody>
        </table>
    </form>
    <script type="text/javascript" src="/static/jquery-2.2.1.min.js"></script>
    <script type="text/javascript">
        function Ajaxsubmit(){
           {# 这里应该从表格中获取数据,为了省事这里直接指定了数据 #}
            var host = '1.1.1.1';
            var port = '8000';

            $.ajax({
                {# 提交到后台的url #}
                url:"/ajax_data/",
                {# 提交到后台的方式 #}
                type:'POST',
                {# 要提交的数据,简单数据直接以字典的形式提交 #}
                data:{h:host,p:port},
                {# 提交成功后要执行的函数,函数内容此处省略 #}
                success:function(arg){

                }
            })
        }
    </script>
</body>
</html>

    views.py文件

def ajax_data(request):
# 打印前端POST提交的数据
print request.POST return HttpResponse('ok')

    2 提交多条数据

   在上述的基础上修改jQuery代码

<script>
        function AjaxsubmitSet(){
            var user_arr = [
                {'username':'alex','age':18},
                {'username':'eric','age':28},
                {'username':'rain','age':38},

            ];
           {# Ajax提交 #}
            $.ajax({
                url:"/ajax_data_set/",
                type:'POST',
                data:{data:user_arr},
                success:function(arg){

                }
            })
        }
</script>

    提交后打印的数据如下所示:

<QueryDict: {u'data[1][username]': [u'alex'], u'data[0][username]': [u'eric'], u'data[0][age]': [u'18'], 
u'data[1][age]': [u'28'], u'data[2][username]': [u'rain'], u'data[2][age]': [u'38']}>

    这明显不符合格式要求,需要我们进一步进行处理,继续修改Ajax提交代码如下:

<script>
        function AjaxsubmitSet(){
            var user_arr = [
                {'username':'alex','age':18},
                {'username':'eric','age':28},
                {'username':'rain','age':38},
            ];

            $.ajax({
                {# Ajax提交url #}
                url:"/ajax_data_set/",
                {# Ajax提交方式 #}
                type:'POST',
                {# Ajax以原生的数据格式进行提交 #}
                tradition:true,
                {# Ajax提交只能处理字符粗,不能处理字典,这里把字典转换成字符串形式 #}
                data:{data:Json.stringify(user_arr)},
                success:function(arg){

                }
            })
        }
    </script>

   3 进一步改进规范的写法

   views.py文件的修改

import json
# 后台向前端返回数据
def ajax_data(request):
    # 设置初始的返回值
    ret = {'status':True,'error':''}
    # 捕捉错误
    try:
        print request.POST
    except Exception,e:
        #异常时,ret[status] = False
        ret['status'] = False
        # 注意这里的str,这里是把e封装成字符串形式
        ret['error'] = str(e)
    # 由于ret是字典形式,但是HttpResponse只能返回字符串,所以这里把ret通过json.dumps()转换成字符串形式
    return HttpResponse(json.dumps(ret))

   jQuery部分的修改

<script>
        function Ajaxsubmit(){
            var user_arr = [
                {'username':'alex','age':18},
                {'username':'eric','age':28},
                {'username':'rain','age':38},

            ];
           {# Ajax提交数据 #}
            $.ajax({
                {# Ajax提交url #}
                url:"/ajax_data/",
                {# Ajax以POST方式提交 #}
                type:'POST',
                {# Ajax以原生形式提交数据 #}
                tradition: true,
                {# Ajax只能提交字符串数据,这里把字典转换为字符串 #}
                data:{data:JSON.stringify(user_arr)},
                {# Ajax提交执行成功后的执行代码,arg是后台返回的数据,切记 #}
                success:function(arg){
                 //这里把后台返回的字符串arg转换为字典形式
                    var callback_dict = $.parseJSON(arg);
                 //这里只做简单的判断,判断后台返回的是否为空
                    if(callback_dict){
                        //不为空,则执行成功了
                        alert('提交成功')
                    }else{
                        //否则,执行失败了
                        alert(callback_dict.error)
                    }
                }
            })
        }
</script>

 

 

 

 

参考资料:

    http://www.cnblogs.com/wupeiqi/articles/5246483.html

    http://www.cnblogs.com/luotianshuai/p/5278175.html

 

posted on 2016-03-01 21:22  人生苦短,python当歌  阅读(826)  评论(0编辑  收藏  举报