django中的Form有个很重要的功能:验证用户输入

 

而验证用户输入也可以分为2种:

  (1)前端本身的验证,例如:字段是否可为空,手机号码格式是否正确等;

  (2)前端输入数据和后台数据库数据的验证,例如:注册的用户名是否已存在,邮箱是否注册过等;

 

本次主要针对第二种情况进行介绍,要实现前后端的数据验证我们可以使用ajax,也可以使用django form的clean_<fieldname>()函数。

下面先看clean_<fieldname>():

一个简单的添加用户的页面:

提交之后对用户进行后台验证,如果存在则会提示。

 

由上图我们可以的看到效果,具体实现代码:

html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">  
    <title>资源管理系统 - 人员管理</title>
    <meta name="description" content="">
    <meta name="author" content="templatemo">
    <link href="/static/css/font-awesome.min.css" rel="stylesheet">
    <link href="/static/css/bootstrap.min.css" rel="stylesheet">
    <link href="/static/css/templatemo-style.css" rel="stylesheet">

  </head>
  <body>  
    <!-- Left column -->
    <div class="templatemo-flex-row">
      <div class="templatemo-sidebar">
        <div class="profile-photo-container">
          <img src="/static/images/logo.png" alt="Profile Photo" class="img-responsive">
          <div class="profile-photo-overlay"></div>
        </div>
        <header class="templatemo-site-header">
          <div class="square"></div>
          <h1>{{ user }}</h1>
        </header>

        <nav class="templatemo-left-nav">          
          <ul>
            <li><a href="/main/index/"><i class="fa fa-home fa-fw"></i>首页</a></li>
            <li><a href="/main/managemachine/"><i class="fa fa-users fa-fw"></i>管理主机</a></li>
            <li><a href="/main/manageuser/" class="active"><i class="fa fa-users fa-fw"></i>管理用户</a></li>
            <li><a href="/main/managegroup/"><i class="fa fa-users fa-fw"></i>管理属组</a></li>
            <li><a href="/main/manageidc/"><i class="fa fa-users fa-fw"></i>管理机房</a></li>
            <li><a href="/main/managecity/"><i class="fa fa-users fa-fw"></i>管理城市</a></li>
            <li><a href="/main/managerecord/"><i class="fa fa-users fa-fw"></i>巡检记录</a></li>
            <li><a href="/main/maps/"><i class="fa fa-map-marker fa-fw"></i>地图</a></li>
            <li><a href="/main/logout/"><i class="fa fa-eject fa-fw"></i>退出</a></li>
          </ul>  
        </nav>
      </div>
      <!-- Main content --> 
      <div class="templatemo-content col-1 light-gray-bg">

        <div class="templatemo-content-container">
          <div class="templatemo-content-widget no-padding">
            <div class="panel panel-default table-responsive">
              <table class="table table-striped table-bordered templatemo-user-table">
                <thead>
                  <tr>
                    <td>序号</td>
                    <td>用户名</td>
                    <td>部门</td>
                    <td>职位</td>
                    <td>电话</td>
                    <td>邮箱</td>
                    <td>编辑</td>
                    <td>删除</td>
                  </tr>
                </thead>
                <tbody>
                  {% for item in ret %}
                    <tr>
                        <td class="uid">{{ item.0 }}</td>
                        <td>{{ item.1 }}</td>
                        <td>{{ item.2 }}</td>
                        <td>{{ item.3 }}</td>
                        <td>{{ item.4 }}</td>
                        <td>{{ item.5 }}</td>
                        <td class="c1 templatemo-link"><a href="/main/updateuser/?g={{ item.0 }}">Edit</a></td>
                        <td class="c2 templatemo-link">Delete</td>
                    </tr>
                  {% endfor %}
                </tbody>
              </table>
            </div>
          </div>
          <div class="templatemo-flex-row flex-content-row">
            <div class="col-1">
              <div class="panel panel-default margin-10">
                <div class="panel-heading"><h2 class="text-uppercase">添加用户</h2></div>
                <div class="panel-body">
                  <form action="/main/manageuser/" class="templatemo-login-form" method="POST">
                    <div class="form-group">
                      <label for="inputEmail">角色</label><span style="color: red"> *</span>
                      {{ data.role_choice }}
                    </div>
                    <div class="form-group">
                      <label for="inputEmail">用户名</label><span style="color: red"> *</span>
                      {{ data.username }}
                      {% if data.errors.username %}
                        <span style="color: red">{{ data.errors.username.0 }}</span>
                      {% endif %}
                    </div>
                    <div class="form-group">
                      <label for="inputEmail">密码</label><span style="color: red"> *</span>
                      {{ data.password }}
                    </div>
                    <div class="form-group">
                      <label for="inputEmail">确认密码</label><span style="color: red"> *</span>
                      {{ data.confirm_password }}
                      {% if data.errors.confirm_password %}
                        <span style="color: red">{{ data.errors.confirm_password.0 }}</span>
                      {% endif %}
                    </div>
                    <div class="form-group">
                      <label for="inputEmail">职位</label><span style="color: red"> *</span>
                      {{ data.job_choice }}
                    </div>
                    <div class="form-group">
                      <label for="inputEmail">邮箱</label>
                      {{ data.email }}
                    </div>
                    <div class="form-group">
                      <label for="inputEmail">电话</label>
                      {{ data.phone }}
                      {% if data.errors.phone %}
                        <span style="color: red">{{ data.errors.phone.0 }}</span>
                      {% endif %}
                    </div>
                    <div class="form-group">
                      <input type="submit" class="templatemo-blue-button" value="提交"/>
                    </div>
                  </form>
                </div>
              </div>              
            </div>
          </div>
        </div> <!-- Second row ends -->
          <div class="pagination-wrap">
            <ul class="pagination">
              <li><a href="#">1</a></li>
              <li><a href="#">2</a></li>
              <li class="active"><a href="#">3 <span class="sr-only">(current)</span></a></li>
              <li><a href="#">4</a></li>
              <li><a href="#">5</a></li>
              <li>
                <a href="#" aria-label="Next">
                  <span aria-hidden="true"><i class="fa fa-play"></i></span>
                </a>
              </li>
            </ul>
          </div>          
          <footer class="text-right">
            <p>Copyright © 2084 好医生运维部 | Designed by 无名小妖</p>
          </footer>         
        </div>
    </div>

  </body>
</html>

  

from:

class InsertForm(forms.Form):
    """添加用户验证"""
    # django给标签加sytle,关键参数widget ,forms.TextInput 表示生成type="text"的input标签,改成Textarea则生成<textarea>标签
    rolechoice = (
        (1, '管理员'),
        (2, '普通用户')
    )
    role_choice = forms.IntegerField(widget=forms.Select(choices=rolechoice, attrs={'class': 'form-control'}), )
    username = forms.CharField(required=True, widget=forms.TextInput(attrs={'class': 'form-control'}))
    password = forms.CharField(required=True, widget=forms.PasswordInput(attrs={'class': 'form-control'}),
                               min_length=6,
                               max_length=10,
                               error_messages={'required': '密码不能为空', 'min_length': '至少6位',
                                               'max_length': '至多10位'})
    confirm_password = forms.CharField(required=True,
                                       widget=forms.PasswordInput(attrs={'class': 'form-control'}),
                                       min_length=6,
                                       max_length=10,
                                       error_messages={'required': '密码不能为空', 'min_length': '至少6位',
                                                       'max_length': '至多10位'})
    email = forms.EmailField(widget=forms.TextInput(attrs={'class': 'form-control'}),)
    # 自定制验证方法关键就是参数validators,和自己的函数关联起来
    phone = forms.CharField(validators=[mobile_validate, ], widget=forms.TextInput(attrs={'class': 'form-control'}),)
    # 获取数据库中的职位信息,显示在页面上
    userjob = UserJob.objects.all().values_list('job_id', 'job_name')
    # list indices must be integers or slices, not str 【此处不能用forms.CharField】
    job_choice = forms.IntegerField(widget=forms.Select(choices=userjob, attrs={'class': 'form-control'}))

    def clean_username(self):
        un = self.cleaned_data['username']
        user = UserInfo.objects.filter(user_name=un)
        if user:
            raise ValidationError('用户名已存在!', code='valid')
        return self.cleaned_data['username']

    def clean_confirm_password(self):
        p1 = self.cleaned_data['password']
        p2 = self.cleaned_data['confirm_password']
        if p1 != p2:
            print(p2)
            raise forms.ValidationError('两次密码不一致!')
        return self.cleaned_data

    def __init__(self, *args, **kwargs):
        """
        实时获取数据相应数据(否则数据库添加的新数据,在页面无法显示)
        :param args:
        :param kwargs:
        """
        super(InsertForm, self).__init__(*args, **kwargs)
        self.fields['job_choice'].widget.choices = UserJob.objects.all().values_list('job_id', 'job_name')

  

我们可以重点看 clean_username 函数,由于我们是要验证用户名(对应html 中name=username的input标签,此处我们是通过django from来生成的,可见html的代码),

所以函数名必须叫clean_username,函数内部对后台数据做了提取验证,并返回自定义的错误信息。

 

下面我们看ajax方式:

一个简单的添加城市的页面:

可以看到对数据的验证,代码就不详细贴了,主要看ajax部分:

<script src="/static/js/jquery-2.1.4.min.js"></script>
    <script>
        function DoSubmit() {
            var input_dic = {};
            $('input').each(function () {
                var v = $(this).val();
                var n = $(this).attr('name');
                input_dic[n] = v;
            });
            $.ajax({
                url:'/main/managecity/',
                type:'POST',
                data:input_dic,
                dataType: 'json',
                success: function (msg) {
                    if(msg.status){
                        location.href = '/main/managecity/'
                    }else{
                        $('#id_city_name').each(function () {
                            var tag = document.createElement('span');
                            tag.style = 'color: red';
                            tag.innerText = msg.message;
                            $(this).after(tag);
                        })
                    }
                }
            })
        }

  

获取用户输入的数据,通过ajax传到views中对应的函数,通过函数进行后台数据验证。

views:

def managecity(req):
    username = req.session.get('username')
    ret = City.objects.all()
    msg = {'status': False, 'message': None}
    # 插入数据
    if req.POST:
        fm = CityForm(req.POST)
        if fm.is_valid():
            # 获取表单信息
            city_name = fm.cleaned_data['city_name']
            city = City.objects.filter(city_name=city_name).count()
            if city:
                msg['message'] = '数据已存在!'
            else:
                msg['status'] = True
                City.objects.create(city_name=city_name)
            return HttpResponse(json.dumps(msg))  # 将数据发送给ajax回调函数
        else:
            msg['message'] = '请填写此字段!'
            return HttpResponse(json.dumps(msg))  # 将数据发送给ajax回调函数
    else:
        fm = CityForm()

    return render(req, 'manage-citys.html', {'user': username, 'data': ret, 'city': fm})

  

验证完之后,在通过ajax回调函数将提示信息显示在页面上显示。

 

总结:

这两种方式都实现了对表单数据的后台验证,

django form 的好处是只需要在定义一个函数即可,并且前端是看不到如何实现的,缺点是只能在django框架用;

而ajax在前端是可以通过查看页面代码看到的,好处是不管什么框架都可以用,而且ajax是“偷偷”发数据,页面不会刷新,但是django form会刷新页面;

 

有兴趣 可以看一下clean源码: