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

 

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

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

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

 

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

下面先看clean_<fieldname>():

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

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

 

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

html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
<!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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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源码: