Django框架之Ajax和form组件

一、Django框架之查漏补缺

1)models,字段概况

name = models.CharField(max_length=32)
age = models.IntegerField()
price = models.FloatField()
pub_date = models.DateField()
author = models.CharField(max_length=32,null=False)
gender = models.BooleanField   # 布尔类型
gender = models.NullBooleanField   # 可以为空的布尔类型

cs = models.ForeignKey("Class")  # 一对多的外键

2)csrf_token 的运用,在form表单中运用

<form action="addbook.html" method="POST">
    {% csrf_token %}
    <input type="text" name="title">
    <input type="submit" name="提交">
</form>
csrf_token运用

3)根据唯一键 id 删除(视图不传id方式)

<td>
    <a href="/del_classes.html?nid={{ row.id }}">删除</a>
</td>
del.html
url(r'^del.html$',views.del),
url
def del(request):
    nid = request.GET.get('nid')
    models.Classes.objects.filter(id=nid).delete()
    return redirect('/class.html')
views.del

4)根据唯一键 id 删除(视图传id方式)

<th>
    <a href="/books/delete/{{ book.id }}" class="btn-sm btn-danger">删除</a>
</th>
del.html
url(r'^book_index/delete/(?P<id>\d+)/',views.deletebooks),
url
def deletebooks(request,id):
    Book.objects.filter(id=id).delete()
    return redirect("/book_index")
views.del

 5)根据唯一键 id 编辑

<th>
    <a href="del_classes.html?nid={{ row.id }}">删除</a>
    |
    <a href="edit_classes.html?nid={{ row.id }}">编辑</a>
</th
跳转到编辑的html
url(r'^edit_classes.html$',views.edit),
url
def edit(request):
    if request.method == 'GET':
        nid = request.GET.get(nid)
        obj = models.Classes.objects.filter(id=nid).first()
        return render(request,'edit.html',{'obj':obj})
    elif request.method == 'POST':
        nid = request.GET.get('nid')
        title = request.POST.get('xxoo')
        models.Classes.objects.filter(id=nid).update(title=title)
        return redirect('classes.html')
views.edit(GET,POST)
第一种,推荐第一种
<form method="POST" action="/edit.html?nid={{ obj.id }}">
    <input type="text" name="xxoo" value="{{ obj.title }}">  {#显示默认值#}
    <input type="submit" value="提交">
</form>

第二种
<form method="POST" action="/edit.html">
    <input type="text" name="id" value="{{ obj.id }}" style="display: none">
    <input type="text" name="xxoo" value="{{ obj.title }}">  {#显示默认值#}
    <input type="submit" value="提交">
</form>
编辑的网页html

 6)互斥框,用于bool类型

<p>
    男:<input type="radio" name="gender" value="1">
    女:<input type="radio" name="gender" value="0">
</p>
radio

7)下拉框,用于选择

下拉框,提交get,name=>cs=row.id
<p>
    <select name="cs">
        {% for row in cs_list %}
            <option value="{{ row.id }}">{{ row.title }}</option>
        {% endfor %}
    </select>
</p>
select

 7.1)下拉框,显示默认值

<form method="POST" action="/set_teacher.html?nid={{ nid }}">
    <select multiple size="10" name="teacher_ids">
        {% for item in all_teacher_list %}
            {% if item.id in id_list %}
                默认选择的老师
                <option value="{{ item.id }}" selected="selected">{{ item.name }}</option>
            {% else %}
                <option value="{{ item.id }}">{{ item.name }}</option>
            {% endif %}
        {% endfor %}
    </select>
    <input type="submit" value="提交">
</form>
select2

 二、前端之ajax 应用

1)ajax 使用方法(GET)

Ajax的应用:下载引入jquery
对话框添加,删除,修改
添加:
    $.ajax({
        url:'/add_classes.html',
        type:'POST',
        data:{'username':'root','password':'123'},
        success:function(arg){
            // 回调函数,arg是服务端返回的数据
        }
    })
Ajax的使用

2)ajax 在Django框架中的基本使用

第一步:路由
    url(r'^ajax1.html$',viems.ajax1),
第二部:设置视图函数
def    ajax1(request):
    return render(request,'ajax1.html')
第三部:前端网页,ajax1.html的编写
ajax的使用步骤

 编写第三步,视图返回的前端页面代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .btn{
            display: inline-block;
            padding: 5px 15px;
            background: darkgoldenrod;
            color: white;
            cursor:pointer ;
        }
    </style>
</head>
<body>
    <div>
        <input placeholder="用户名" type="text" id="username">
        <input placeholder="密码" type="password" id="password">
        <div class="btn" onclick="submitForm();">提交</div>
    </div>
    
    <script src="/static/jquery-3.2.1.min.js"></script>
    <script>
        function submitForm() {
            var u = $('#username').val();
            var p = $('#password').val();
            $.ajax({
                url:'/ajax2.html',
                type:'GET',
                data:{username:u,password:p},
                success:function (arg) {
                    console.log(arg);
                }
            })
        }
    </script>
</body>
</html>
ajax1.html

使用ajax方法,悄悄的往ajax2.html发送数据

url(r'^ajax2.html$',views.ajax2),
ajax路由(悄悄发送的网页请求)

最后,ajax视图返回数据

def ajax2(request):
    user = request.GET.get('username')
    pwd = request.GET.get('password')
    import time
    time.sleep(5)
    return HttpResponse('ok')
views.ajax2

3)ajax的POST请求

接第三步,视图返回的前端页面代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .btn{
            display: inline-block;
            padding: 5px 15px;
            background: darkgoldenrod;
            color: white;
            cursor:pointer ;
        }
    </style>

</head>
<body>
    <div>
        <input placeholder="数字" type="text" id="i1">
        +
        <input placeholder="数字" type="text" id="i2">
        <div class="btn" onclick="addForm();">等于</div>
        <input placeholder="数字" type="text" id="i3">
    </div>

    <script src="/static/jquery-3.2.1.min.js"></script>
    <script>
        function addForm() {
            var v1 = $('#i1').val();
            var v2= $('#i2').val();
            $.ajax({
                url:'/ajax3.html',
                type:'POST',
                data:{"v1":v1,"v2":v2},
                success:function (arg) {
{#                    console.log(arg);#}
                    $('#i3').val(arg);
                }
            })
        }
    </script>

</body>
</html>
ajax1.html

ajax请求 url:'/ajax3.html',则

url(r'^ajax3.html$',views.ajax3),
ajax路由

最后视图返回数据

def ajax3(request):
    v1 = request.POST.get('v1')
    v2 = request.POST.get('v2')
    try:
        v3 = int(v1) + int(v2)
    except Exception as e:
        v3 = "输入格式错误"
    return HttpResponse(v3)
view.ajax3

4)ajax删除,使用js删除。减少获取数据库资源

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div>
        <a href="/add_students.html">添加</a>

    </div>
    <div>
        <table border="1">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>姓名</th>
                    <th>年龄</th>
                    <th>性别</th>
                    <th>班级</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                {% for row in stu_list  %}
                    <tr nid="{{ row.id }}">
                        <td>
                            {{ row.id }}
                        </td>
                        <td>
                            {{ row.username }}
                        </td>
                        <td>
                            {{ row.age }}
                        </td>

                        <td>
                            {{ row.gender }}
                        </td>
                        <td>
                            {{ row.cs.titile }}
                        </td>
                        <td>
                            <a href="/del_students.html?nid={{ row.id }}">删除</a>
                            |
                            <a onclick="removeStudent(this);" href="javascript:void();">Ajax删除</a>
                            |
                            <a href="/edit_students.html?nid={{ row.id }}">编辑</a>
                        </td>
                    </tr>
                {% endfor %}
            </tbody>
        </table>
    </div>
    <script src="/static/jquery-3.1.1.js"></script>
    <script>
        function  removeStudent(ths) {
            var nid = $(ths).parent().parent().attr('nid');
            $.ajax({
                url: '/ajax4.html',
                type: 'GET',
                data: {nid: nid},
                success:function (arg) {
                    if(arg == '成功'){
                        // window.location.reload();    页面刷新,意味着重新获取数据库的资源,即增加了数据库的压力
                        $(ths).parent().parent().remove();    // 根据 arg 的值,说明数据库操作执行成功了,就移除了相应的标签
                    }else{
                        alert(arg);
                    }
                }
            })
        }
    </script>
</body>
</html>
ajax删除.html
def ajax4(request):
    nid = request.GET.get('nid')
    msg = '成功'
    try:
        models.Student.objects.filter(id=nid).delete()
    except Exception as e:
        msg = str(e)
    return HttpResponse(msg)
views.ajax删除

5)使用ajax对模态对话框新增数据。window.location.reload() 简单版

html的模态对话框的编写

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.css"/>
    <link rel="stylesheet" href="/static/plugins/font-awesome/css/font-awesome.css"/>
    <style>
        .icon {
            margin: 0 5px;
        }
    </style>
</head>
<body>
<div class="container">
    <div style="padding: 20px 0;">
        <a class="btn btn-primary" id="addBtn">添加</a>
        <a class="btn btn-danger">删除</a>
    </div>

    <div>
        <table class="table table-bordered table-striped">
            <thead>
            <tr>
                <th>ID</th>
                <th>姓名</th>
                <th>年龄</th>
                <th>性别</th>
                <th>班级</th>
                <th>操作</th>
            </tr>
            </thead>
            <tbody>
            {% for row in stu_list %}
                <tr>
                    <td>{{ row.id }}</td>
                    <td>{{ row.username }}</td>
                    <td>{{ row.age }}</td>
                    <td>{{ row.gender }}</td>
                    <td>{{ row.cs.title }}</td>
                    <td>
                        <a class="glyphicon glyphicon-remove icon"></a><a class="fa fa-pencil-square-o icon"></a>
                    </td>
                </tr>
            {% endfor %}
            </tbody>

        </table>
    </div>
</div>

<!-- Modal -->
<div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
                        aria-hidden="true">&times;</span></button>
                <h4 class="modal-title" id="myModalLabel">创建学生</h4>
            </div>
            <div class="modal-body">

                <form class="form-horizontal">
                    <div class="form-group">
                        <label for="username" class="col-sm-2 control-label">姓名</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" name="username" placeholder="姓名">
                        </div>
                    </div>

                    <div class="form-group">
                        <label for="age" class="col-sm-2 control-label">年龄</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" name="age" placeholder="年龄">
                        </div>
                    </div>

                    <div class="form-group">
                        <label for="age" class="col-sm-2 control-label">性别</label>
                        <div class="col-sm-10">
                            <label class="radio-inline">
                                <input type="radio" name="gender" value="1"></label>
                            <label class="radio-inline">
                                <input type="radio"  name="gender" value="0"></label>
                        </div>
                    </div>

                    <div class="form-group">
                        <label for="age" class="col-sm-2 control-label">班级</label>
                        <div class="col-sm-10">
                            <select class="form-control" name="cls_id">
                                {% for row in cls_list %}
                                    <option value="{{ row.id }}">{{ row.title }}</option>
                                {% endfor %}
                            </select>

                        </div>
                    </div>
                </form>
            </div>
            <div class="modal-footer">
                <span id="errorMsg" style="color: red;"></span>
                <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
                <button type="button" class="btn btn-primary" id="btnSave">保存</button>
            </div>
        </div>
    </div>
</div>

<script src="/static/js/jquery-3.1.1.js"></script>
<script src="/static/plugins/bootstrap/js/bootstrap.js"></script>
模特对话框.html

js代码,触发显示对话框,并触发ajax请求

<script>
    $(function () {
        bindEvent();
        bindSave();
    });
    
    // 点击事件,触发显示对话框
    function bindEvent() {
        $('#addBtn').click(function () {
            $('#addModal').modal('show');
        })
    }
    
    // 点击保存,触发数据库请求保存事件
    function bindSave() {
        $('#btnSave').click(function () {
            var postData = {};  // 新增数据的字典
            
            // each 循环寻找每一个input 和select标签
            $('#addModal').find('input,select').each(function () {
                var v = $(this).val();
                var n = $(this).attr('name');
                if(n=='gender'){
                    if($(this).prop('checked')){
                        postData[n] = v;
                    }
                }else{
                    postData[n] = v;
                }
            });
            $.ajax({
                url: '/add_student/',
                type: 'POST',
                data: postData,
                success:function (arg) {
                    // arg是字符串
                    // JSON.parse将字符串转换成字典, json.loads
                    var dict = JSON.parse(arg);
                    if(dict.status){
                        window.location.reload();
                    }else {
                        $('#errorMsg').text(dict.message);
                    }
                }
            })
        });
    }

</script>
接上的script

django路由设置

url(r'^students/', views.students),
url(r'^add_student/', views.add_student),
django路由设置

针对ajax请求的视图函数

# ajax 请求返回数据
def add_student(request):
    response = {'status':True,'message': None}
    try:
        u = request.POST.get('username')
        a = request.POST.get('age')
        g = request.POST.get('gender')
        c = request.POST.get('cls_id')
        models.Student.objects.create(
            username=u,
            age=a,
            gender=g,
            cs_id=c
        )
    except Exception as e:
        response['status'] = False
        response['message'] = '用户输入错误'
    import json
    result = json.dumps(response,ensure_ascii=False)
    return HttpResponse(result)
ajax.add

缺陷,ajax请求使用的是window.location.reload() ,会再次请求数据库

6)使用ajax对模态对话框新增数据。获取到新增的数据,主动添加标签。复杂版

针对ajax代码的修改

    function bindEvent() {
        $('#addBtn').click(function () {
            $('#addModal').modal('show');
        })
    }
    function bindSave() {

        $('#btnSave').click(function () {
            var postData = {};
            $('#addModal').find('input,select').each(function () {
                var v = $(this).val();
                var n = $(this).attr('name');
                if(n=='gender'){
                    if($(this).prop('checked')){
                        postData[n] = v;
                    }
                }else{
                    postData[n] = v;
                }
            });

            /*
            postData = {
                 username: 'asdf',
                 age:18,
                 gender: 1,
                 cls_id: 2
            }
             */

            $.ajax({
                url: '/add_student/',
                type: 'POST',
                data: postData,
                success:function (arg) {
                    // arg是字符串
                    // JSON.parse将字符串转换成字典, json.loads
                    var dict = JSON.parse(arg);
                    if(dict.status){
                        /*
                        postData = {
                             username: 'asdf',
                             age:18,
                             gender: 1,
                             cls_id: 2
                        }
                        自增id  = dict.data
                         */
                        createRow(postData,dict.data);
                        $('#addModal').modal('hide');
                        // window.location.reload();
                    }else {
                        $('#errorMsg').text(dict.message);
                    }
                }
            })
        });
    }
    function createRow(postData,nid) {
        var tr = document.createElement('tr');
        $(tr).attr('nid',nid);

        var tdId = document.createElement('td');
        tdId.innerHTML = nid;
        $(tr).append(tdId);

        var tdUser = document.createElement('td');
        tdUser.innerHTML = postData.username;
        $(tr).append(tdUser);

        var tdAge = document.createElement('td');
        tdAge.innerHTML = postData.age;
        $(tr).append(tdAge);


        var tdGender = document.createElement('td');
        if(postData.gender == "0"){
            tdGender.innerHTML = 'False';
        }else{
             tdGender.innerHTML = 'True';
        }
        $(tr).append(tdGender);


        var tdClass = document.createElement('td');
        var text = $('select[name="cls_id"]').find('option[value="'+ postData.cls_id +'"]').text();
        tdClass.innerHTML = text;
        $(tr).append(tdClass);

        var tdHandle = '<td> <a class="glyphicon glyphicon-remove icon del-row"></a><a class="fa fa-pencil-square-o icon edit-row"></a> </td>';
        $(tr).append(tdHandle);

        $('#tb').append(tr);
    }
增加创建的标签
def add_student(request):
    response = {'status':True,'message': None,'data':None}
    try:
        u = request.POST.get('username')
        a = request.POST.get('age')
        g = request.POST.get('gender')
        c = request.POST.get('cls_id')
        obj = models.Student.objects.create(
            username=u,
            age=a,
            gender=g,
            cs_id=c
        )
        response['data'] = obj.id   # 传送id 给前端
    except Exception as e:
        response['status'] = False
        response['message'] = '用户输入错误'

    result = json.dumps(response,ensure_ascii=False)
    return HttpResponse(result)
ajax.add

 7)对于删除事件的方法,事件委托

事件委托的语法
$('要绑定标签的上级标签').on('click','要绑定的标签',function(){})

在jQuery版本1和2时,还有下面的用法
$('要绑定标签的上级标签').delegate('要绑定的标签','click',function(){})
事件委托语法

前端标签代码如下

<table class="table table-bordered table-striped">
    <thead>
    <tr>
        <th>ID</th>
        <th>姓名</th>
        <th>年龄</th>
        <th>性别</th>
        <th>班级</th>
        <th>操作</th>
    </tr>
    </thead>
    <tbody id="tb">
    {% for row in stu_list %}
        <tr nid="{{  row.id }}">
            <td na="nid">{{ row.id }}</td>
            <td na="user">{{ row.username }}</td>
            <td na="age">{{ row.age }}</td>
            <td na="gender">{{ row.gender }}</td>
            <td na="cls_id" cid="{{ row.cs_id }}">{{ row.cs.title }}</td>
            <td>
                <a class="glyphicon glyphicon-remove icon del-row"></a><a class="fa fa-pencil-square-o icon edit-row"></a>
            </td>
        </tr>
    {% endfor %}
    </tbody>
</table>
table标签内容

在不使用事件委托时,如果不刷新页面,则新增加的标签,没有绑定方法

function bindDel() {
    $('.del-row').click(function () {
        $('#delModal').modal('show');
        // 回去当前行的ID
        var rowId = $(this).parent().parent().attr('nid');
        $('#delNid').val(rowId);
    })
}
普通删除事件绑定

使用事件委托的绑定事件方法

function bindDel() {
    $('#tb').on('click','.del-row',function () {
        // #tb标签是del-row标签的父标签,click事件委托给了父标签
        $('#delModal').modal('show');
        // 回去当前行的ID
        var rowId = $(this).parent().parent().attr('nid');
        $('#delNid').val(rowId);
    })
}
事件委托

8)模态对话框的标签获取方式优化

复杂版
var postData = {};
$('#addModal').find('input,select').each(function () {
    var v = $(this).val();
    var n = $(this).attr('name');
    if(n=='gender'){
        if($(this).prop('checked')){
            postData[n] = v;
        }
    }else{
        postData[n] = v;
    }
});

优化版
- var data = $('#fmForm表单的ID').serialize();
 $.ajax({
    data: $('#fm').serialize()
 })
ajax.form.serialize优化

9)ajax使用总结

1. json虚拟化
    Python序列化
        字符串 = json.dumps(对象)    对象->字符串
        对象 = json.loads(字符串)    字符串->对象
        
    JavaScript:
        字符串 = JSON.stringify(对象) 对象->字符串
        对象 = JSON.parse(字符串)     字符串->对象
        
    应用场景:
        数据传输时,
            发送:字符串
            接收:字符串 -> 对象
2. ajax

    $.ajax({
        url: 'http//www.baidu.com',
        type: 'GET',
        data: {'k1':'v1'},
        success:function(arg){
            // arg是字符串类型
            // var obj = JSON.parse(arg)
        }
    })
    
    
    $.ajax({
        url: 'http//www.baidu.com',
        type: 'GET',
        data: {'k1':'v1'},
        dataType: 'JSON',
        success:function(arg){
            // arg是对象
        }
    })
    
    
    $.ajax({
        url: 'http//www.baidu.com',
        type: 'GET',
        data: {'k1':[1,2,3,4]},
        dataType: 'JSON',
        success:function(arg){
            // arg是对象
        }
    })
    
    发送数据时:
        data中的v
        
        a. 只是字符串或数字
            $.ajax({
                url: 'http//www.baidu.com',
                type: 'GET',
                data: {'k1':'v1'},
                dataType: 'JSON',
                success:function(arg){
                    // arg是对象
                }
            })
        b. 包含属组
            $.ajax({
                url: 'http//www.baidu.com',
                type: 'GET',
                data: {'k1':[1,2,3,4]},
                dataType: 'JSON',
                traditional: true,
                success:function(arg){
                    // arg是对象
                }
            })
            
        c. 传字典
        
            b. 包含属组
            $.ajax({
                url: 'http//www.baidu.com',
                type: 'GET',
                data: {'k1': JSON.stringify({}) },
                dataType: 'JSON',
                success:function(arg){
                    // arg是对象
                }
            })
            
    
    
3. 事件委托

    $('要绑定标签的上级标签').on('click','要绑定的标签',function(){})

    $('要绑定标签的上级标签').delegate('要绑定的标签','click',function(){})

4. 总结

        新URL方式:
            - 独立的页面
            - 数据量大或条目多
            
        对话框方式:
            - 数据量小或条目少
                -增加,编辑
                    - Ajax: 考虑,当前页;td中自定义属性
                    - 页面(***)
                
        删除:
            对话框
ajax使用总结

 三、django的form组件:表单验证,错误提示,生成 html

1)Form组件:最基本功能

- 对用户请求的验证
    - AJax
    - Form
- 生成HTML代码

a. 创建一个类
b. 类中创建字段(包含正则表达式)
c. GET
    obj = Fr()
    obj.user = > 自动生成HTML
    
d. POST
    obj = Fr(request.POST)
    if obj.is_valid():
        obj.cleaned_data
    else:
        obj.errors
        return .... obj
form组件最基本功能概况

2)Form的基本运用

前端代码编写(form组件生产的的html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form id="fm" action="/f1.html" method="POST">
        <p>{{ obj.user }}{{ obj.errors.user.0 }}</p>
        <p>{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p>
        <p>{{ obj.age }}{{ obj.errors.age.0 }}</p>
        <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
        <input type="submit" value="提交" />
    </form>
    <script src="/static/jquery-3.1.1.js"></script>

</body>
</html>
f1.html

路由映射至视图函数

url(r'^f1.html$', views.f1),
路由映射

视图函数(form组件运用)

from django.shortcuts import render
from django.shortcuts import redirect
from django.shortcuts import HttpResponse


from django import forms
from django.forms import fields
class F1Form(forms.Form):
    user = fields.CharField(
        max_length=18,
        min_length=6,
        required=True,
        error_messages={
            'required': '用户名不能为空',
            'max_length': '太长了',
            'min_length': '太短了',
            'invalid':'..'
        }
    )
    pwd = fields.CharField(required=True,min_length=32)
    age = fields.IntegerField(
        required=True,
        error_messages={
            'required':'年龄不能为空',
            'invalid':'年龄必须为数字'
        }
    )
    email = fields.EmailField(
        required=True,
        min_length=8,
        error_messages={
            'required':'邮箱不能为空'
            'invalid':'邮箱格式错误'
        }
    )


def f1(request):
    if request.method == 'GET':
        obj = F1Form()
        return render(request,'f1.html',{'obj':obj})
    else:
        obj = F1Form(request.POST)
        # 是否全部验证成功
        if obj.is_valid():
            # 用户提交的数据
            print('验证成功',obj.cleaned_data)
            return redirect('http://www.xiaohuar.com')
        else:
            print('验证失败',obj.errors)
            return render(request, 'f1.html',{'obj':obj})
views.f1.form组件

 3)Form组件生成前端代码,可获取编辑默认值

model模型表设计

from django.db import models

class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    email = models.EmailField(max_length=32)
model.py

创建forms表单验证类

from django import forms as dforms
from django.forms import fields

class UserForm(dforms.Form):
    username = fields.CharField()
    email = fields.EmailField()
forms.py

urls路由定义

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^users/', views.users),
    url(r'^add_user/', views.add_user),
    url(r'^edit_user-(\d+)/', views.edit_user),
]
url路由

视图函数

from django.shortcuts import render
from django.shortcuts import redirect
from app01 import models

def users(request):
    user_list = models.UserInfo.objects.all()
    return render(request,'users.html',{'user_list':user_list})
    
from app01.forms import UserForm
def add_user(request):
    if request.method == 'GET':
        obj = UserForm()
        print('==>前端代码',obj)      # 生成html代码传给前端
        return render(request,'add_user.html',{'obj':obj})
    else:
        obj = UserForm(request.POST)
        if obj.is_valid():
            models.UserInfo.objects.create(**obj.cleaned_data)
            return redirect('/users/')
        else:
            return render(request,'add_user.html',{'obj':obj})
            
def edit_user(request,nid):
    if request.method == "GET":
        data = models.UserInfo.objects.filter(id=nid).first()
        obj = UserForm({'username':data.username,'email':data.email})
        return render(request,'edit_user.html',{'obj':obj,'nid':nid})
    else:
        obj = UserForm(request.POST)
        if obj.is_valid():
            models.UserInfo.objects.filter(id=nid).update(**obj.cleaned_data)
            return redirect('/users/')
        else:
            return render(request,'edit_user.html',{'obj':obj,'nid':nid})
views

templates前端文件创建

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="/add_user/">添加</a>
    <ul>
        {% for row in user_list %}
            <li>{{ row.id }}-{{ row.username }}-{{ row.email }} <a href="/edit_user-{{ row.id }}/">编辑</a></li>
        {% endfor %}
    </ul>
</body>
</html>
users.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/add_user/" method="post" novalidate>
        {% csrf_token %}
        <p>{{ obj.username }}{{ obj.errors.username.0 }}</p>
        <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
        <input type="submit" value="提交" />
    </form>
</body>
</html>
add_user.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/edit_user-{{ nid }}/" method="POST" novalidate>
        {% csrf_token %}
        <p>{{ obj.username }}{{ obj.errors.username.0 }}</p>
        <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
        <input type="submit" value="提交" />
    </form>
</body>
</html>
edit_user.html

 使用流程信息归纳总结

定义表单验证规则
    form.py
        from django import forms as dforms
        from django.forms import fields
        class UserForm(dforms.Form):
            username = fields.CharField()
            email = fields.EmailField()
------------------------------------------------------------------    
对于添加:    
    views.py
        from app01.forms import UserForm
        def add_user(request):
            if request.method == 'GET':
                obj = UserForm()
                print('==>前端代码',obj)      # 生成html代码传给前端
                return render(request,'add_user.html',{'obj':obj})
            else:
                obj = UserForm(request.POST)
                if obj.is_valid():
                    models.UserInfo.objects.create(**obj.cleaned_data)
                    return redirect('/users/')
                else:
                    return render(request,'add_user.html',{'obj':obj})
    add_user.html            
        <body>
            <form action="/add_user/" method="post" novalidate>        # novalidate 取消默认的浏览器的验证
                {% csrf_token %}
                <p>{{ obj.username }}{{ obj.errors.username.0 }}</p>
                <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
                <input type="submit" value="提交" />
            </form>
        </body>
------------------------------------------------------------------    
对于编辑:
    views.py:
        def edit_user(request,nid):
            if request.method == "GET":
                data = models.UserInfo.objects.filter(id=nid).first()
                obj = UserForm({'username':data.username,'email':data.email})
                return render(request,'edit_user.html',{'obj':obj,'nid':nid})
            else:
                obj = UserForm(request.POST)
                if obj.is_valid():
                    models.UserInfo.objects.filter(id=nid).update(**obj.cleaned_data)
                    return redirect('/users/')
                else:
                    return render(request,'edit_user.html',{'obj':obj,'nid':nid})
    edit_user.html:    
        <body>
            <form action="/edit_user-{{ nid }}/" method="POST" novalidate>
                {% csrf_token %}
                <p>{{ obj.username }}{{ obj.errors.username.0 }}</p>
                <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
                <input type="submit" value="提交" />
            </form>
        </body>
特别注意:模型生成的字段名最好与表单验证名一致,使用的html的变量名也应该使用模型的字段名
小结

 四、深入了解Form组件

1)Django的Form主要具有一下几大功能:

1)生成HTML标签
2)验证用户数据(显示错误信息)
3)HTML Form提交保留上次提交数据
4)初始化页面显示内容

2)对Form功能小测试

2.1)创建Form类

from django.forms import Form
from django.forms import widgets
from django.forms import fields
 
class MyForm(Form):
    user = fields.CharField(
        widget=widgets.TextInput(attrs={'id': 'i1', 'class': 'c1'})
    )
 
    gender = fields.ChoiceField(
        choices=((1, ''), (2, ''),),
        initial=2,
        widget=widgets.RadioSelect
    )
 
    city = fields.CharField(
        initial=2,
        widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
    )
 
    pwd = fields.CharField(
        widget=widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
    )
View Code

2.2) View函数处理

from django.shortcuts import render, redirect
from .forms import MyForm
 
 
def index(request):
    if request.method == "GET":
        obj = MyForm()
        return render(request, 'index.html', {'form': obj})
    elif request.method == "POST":
        obj = MyForm(request.POST, request.FILES)
        if obj.is_valid():
            values = obj.clean()
            print(values)
        else:
            errors = obj.errors
            print(errors)
        return render(request, 'index.html', {'form': obj})
    else:
        return redirect('http://www.google.com')
View Code

2.3)生成html

<form action="/" method="POST" enctype="multipart/form-data">
    <p>{{ form.user }} {{ form.user.errors }}</p>
    <p>{{ form.gender }} {{ form.gender.errors }}</p>
    <p>{{ form.city }} {{ form.city.errors }}</p>
    <p>{{ form.pwd }} {{ form.pwd.errors }}</p>
    <input type="submit"/>
</form>
View Code
<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    
        {{ form.xxoo.label }}
        {{ form.xxoo.id_for_label }}
        {{ form.xxoo.label_tag }}
        {{ form.xxoo.errors }}
        <p>{{ form.user }} {{ form.user.errors }}</p>
        <input type="submit" />
</form>
其他标签有

2.3)前端另一种简单写法,但不推荐,无法定制css属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>test2</h3>
    {#  不推荐,无法定制标签  #}
    {{ obj.as_p }}
    <br>
    <ul>{{ obj.as_ul }}</ul>
    <br>
    <table>{{ obj.as_table }}</table>

</bo
{{ obj.as_p }}.html

3)创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;

Field
    required=True,               是否允许为空
    widget=None,                 HTML插件
    label=None,                  用于生成Label标签或显示内容
    initial=None,                初始值
    help_text='',                帮助信息(在标签旁边显示)
    error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
    show_hidden_initial=False,   是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
    validators=[],               自定义验证规则
    localize=False,              是否支持本地化
    disabled=False,              是否可以编辑
    label_suffix=None            Label内容后缀
 
 
CharField(Field)
    max_length=None,             最大长度
    min_length=None,             最小长度
    strip=True                   是否移除用户输入空白
 
IntegerField(Field)
    max_value=None,              最大值
    min_value=None,              最小值
 
FloatField(IntegerField)
    ...
 
DecimalField(IntegerField)
    max_value=None,              最大值
    min_value=None,              最小值
    max_digits=None,             总长度
    decimal_places=None,         小数位长度
 
BaseTemporalField(Field)
    input_formats=None          时间格式化   
 
DateField(BaseTemporalField)    格式:2015-09-01
TimeField(BaseTemporalField)    格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
 
DurationField(Field)            时间间隔:%d %H:%M:%S.%f
    ...
 
RegexField(CharField)
    regex,                      自定制正则表达式
    max_length=None,            最大长度
    min_length=None,            最小长度
    error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}
 
EmailField(CharField)      
    ...
 
FileField(Field)
    allow_empty_file=False     是否允许空文件
 
ImageField(FileField)      
    ...
    注:需要PIL模块,pip3 install Pillow
    以上两个字典使用时,需要注意两点:
        - form表单中 enctype="multipart/form-data"
        - view函数中 obj = MyForm(request.POST, request.FILES)
 
URLField(Field)
    ...
 
 
BooleanField(Field)  
    ...
 
NullBooleanField(BooleanField)
    ...
 
ChoiceField(Field)
    ...
    choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
    required=True,             是否必填
    widget=None,               插件,默认select插件
    label=None,                Label内容
    initial=None,              初始值
    help_text='',              帮助提示
 
 
ModelChoiceField(ChoiceField)
    ...                        django.forms.models.ModelChoiceField
    queryset,                  # 查询数据库中的数据
    empty_label="---------",   # 默认空显示内容
    to_field_name=None,        # HTML中value的值对应的字段
    limit_choices_to=None      # ModelForm中对queryset二次筛选
     
ModelMultipleChoiceField(ModelChoiceField)
    ...                        django.forms.models.ModelMultipleChoiceField
 
 
     
TypedChoiceField(ChoiceField)
    coerce = lambda val: val   对选中的值进行一次转换
    empty_value= ''            空值的默认值
 
MultipleChoiceField(ChoiceField)
    ...
 
TypedMultipleChoiceField(MultipleChoiceField)
    coerce = lambda val: val   对选中的每一个值进行一次转换
    empty_value= ''            空值的默认值
 
ComboField(Field)
    fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
                               fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
 
MultiValueField(Field)
    PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
 
SplitDateTimeField(MultiValueField)
    input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
    input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
 
FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
    path,                      文件夹路径
    match=None,                正则匹配
    recursive=False,           递归下面的文件夹
    allow_files=True,          允许文件
    allow_folders=False,       允许文件夹
    required=True,
    widget=None,
    label=None,
    initial=None,
    help_text=''
 
GenericIPAddressField
    protocol='both',           both,ipv4,ipv6支持的IP格式
    unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
 
SlugField(CharField)           数字,字母,下划线,减号(连字符)
    ...
 
UUIDField(CharField)           uuid类型
form字段

注:UUID是根据MAC以及当前时间等创建的不重复的随机字符串

>>> import uuid

    # make a UUID based on the host ID and current time
    >>> uuid.uuid1()    # doctest: +SKIP
    UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')

    # make a UUID using an MD5 hash of a namespace UUID and a name
    >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
    UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')

    # make a random UUID
    >>> uuid.uuid4()    # doctest: +SKIP
    UUID('16fd2706-8baf-433b-82eb-8c7fada847da')

    # make a UUID using a SHA-1 hash of a namespace UUID and a name
    >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
    UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')

    # make a UUID from a string of hex digits (braces and hyphens ignored)
    >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')

    # convert a UUID to a string of hex digits in standard form
    >>> str(x)
    '00010203-0405-0607-0809-0a0b0c0d0e0f'

    # get the raw 16 bytes of the UUID
    >>> x.bytes
    b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'

    # make a UUID from a 16-byte string
    >>> uuid.UUID(bytes=x.bytes)
    UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
uuid

重点字段

- 字段
    用于保存正则表达式
    ChoiceField *****
    MultipleChoiceField
    CharField
    IntegerField
    DecimalField
    DateField
    DateTimeField
    EmailField
    GenericIPAddressField
    FileField
    RegexField
- HTML插件
    用于生成HTML标签
重点字段

 4)Django内置插件,生成html属性

TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget
内置插件生成html属性

4.1)常用选择插件

# 单radio,值为字符串
# user = fields.CharField(
#     initial=2,
#     widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
# )
 
# 单radio,值为字符串
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.RadioSelect
# )
 
# 单select,值为字符串
# user = fields.CharField(
#     initial=2,
#     widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
# )
 
# 单select,值为字符串
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.Select
# )
 
# 多选select,值为列表
# user = fields.MultipleChoiceField(
#     choices=((1,'上海'),(2,'北京'),),
#     initial=[1,],
#     widget=widgets.SelectMultiple
# )
 
 
# 单checkbox
# user = fields.CharField(
#     widget=widgets.CheckboxInput()
# )
 
 
# 多选checkbox,值为列表
# user = fields.MultipleChoiceField(
#     initial=[2, ],
#     choices=((1, '上海'), (2, '北京'),),
#     widget=widgets.CheckboxSelectMultiple
# )
View Code

5)在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 ***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的。

重点。数据库更新,html获取到的数据库,存在内存,下次访问并没有更新。需要重启数据库。下面是解决方法

5.1)方法一

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
 
class MyForm(Form):
 
    user = fields.ChoiceField(
        # choices=((1, '上海'), (2, '北京'),),
        initial=2,
        widget=widgets.Select
    )
 
    def __init__(self, *args, **kwargs):
        super(MyForm,self).__init__(*args, **kwargs)
        # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),)
        # 或
        self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')
推荐方法

5.2)方法二:使用django提供的ModelChoiceField和ModelMultipleChoiceField字段来实现

from django import forms
from django.forms import fields
from django.forms import widgets
from django.forms import models as form_model
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
 
class FInfo(forms.Form):
    authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
    # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())
不推荐

6)自定义验证规则

6.1)方法一:

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
 
class MyForm(Form):
    user = fields.CharField(
        validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
    )
View Code

6.2)方法二

import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
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(Form):
 
 
    title = fields.CharField(max_length=20,
                            min_length=5,
                            error_messages={'required': '标题不能为空',
                                            'min_length': '标题最少为5个字符',
                                            'max_length': '标题最多为20个字符'},
                            widget=widgets.TextInput(attrs={'class': "form-control",
                                                          'placeholder': '标题5-20个字符'}))
 
 
    # 使用自定义验证规则
    phone = fields.CharField(validators=[mobile_validate, ],
                            error_messages={'required': '手机不能为空'},
                            widget=widgets.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'手机号码'}))
 
    email = fields.EmailField(required=False,
                            error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
                            widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))
View Code

6.3)方法三,自定义方法

from django import forms
    from django.forms import fields
    from django.forms import widgets
    from django.core.exceptions import ValidationError
    from django.core.validators import RegexValidator
 
    class FInfo(forms.Form):
        username = fields.CharField(max_length=5,
                                    validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.', 'invalid')], )
        email = fields.EmailField()
 
        def clean_username(self):
            """
            Form中字段中定义的格式匹配完之后,执行此方法进行验证
            :return:
            """
            value = self.cleaned_data['username']
            if "666" in value:
                raise ValidationError('666已经被玩烂了...', 'invalid')
            return value
View Code

6.4)同时生成多个标签进行验证

from django.forms import Form
from django.forms import widgets
from django.forms import fields
 
from django.core.validators import RegexValidator
 
 
############## 自定义字段 ##############
class PhoneField(fields.MultiValueField):
    def __init__(self, *args, **kwargs):
        # Define one message for all fields.
        error_messages = {
            'incomplete': 'Enter a country calling code and a phone number.',
        }
        # Or define a different message for each field.
        f = (
            fields.CharField(
                error_messages={'incomplete': 'Enter a country calling code.'},
                validators=[
                    RegexValidator(r'^[0-9]+$', 'Enter a valid country calling code.'),
                ],
            ),
            fields.CharField(
                error_messages={'incomplete': 'Enter a phone number.'},
                validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid phone number.')],
            ),
            fields.CharField(
                validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.')],
                required=False,
            ),
        )
        super(PhoneField, self).__init__(error_messages=error_messages, fields=f, require_all_fields=False, *args,
                                         **kwargs)
 
    def compress(self, data_list):
        """
        当用户验证都通过后,该值返回给用户
        :param data_list:
        :return:
        """
        return data_list
 
############## 自定义插件 ##############
class SplitPhoneWidget(widgets.MultiWidget):
    def __init__(self):
        ws = (
            widgets.TextInput(),
            widgets.TextInput(),
            widgets.TextInput(),
        )
        super(SplitPhoneWidget, self).__init__(ws)
 
    def decompress(self, value):
        """
        处理初始值,当初始值initial不是列表时,调用该方法
        :param value:
        :return:
        """
        if value:
            return value.split(',')
        return [None, None, None]
初始化数据
View Code

7)form组件使用ajax提交数据验证

7.1)ajax普通验证

from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
class AjaxForm(forms.Form):
    username = fields.CharField()
    user_id = fields.IntegerField(
        widget=widgets.Select(choices=[(0,'alex'),(1,'刘皓宸'),(2,'杨建'),])
    )
    # 自定义方法 clean_字段名
    # 必须返回值self.cleaned_data['username']
    # 如果出错:raise ValidationError('用户名已存在')
    def clean_username(self):
        v = self.cleaned_data['username']
        if models.UserInfo.objects.filter(username=v).count():
            # 整体错了
            # 自己详细错误信息
            raise ValidationError('用户名已存在')
        return v
    def clean_user_id(self):
        return self.cleaned_data['user_id']
定义form规则
def ajax(request):
    if request.method == 'GET':
        obj = AjaxForm()
        return render(request,'ajax.html',{'obj':obj})
    else:
        ret = {'status':'杨建','message':None}
        import json
        obj = AjaxForm(request.POST)
        if obj.is_valid():
            # 跳转到百度
            # return redirect('http://www.baidu.com')
            # if ....
            #     obj.errors['username'] = ['用户名已经存在',]
            # if ....
            #     obj.errors['email'] = ['用户名已经存在',]

            ret['status'] = ''
            return HttpResponse(json.dumps(ret))
        else:
            # print(type(obj.errors))
            # print(obj.errors)
            from django.forms.utils import ErrorDict
            # print(obj.errors.as_ul())
            # print(obj.errors.as_json())
            # print(obj.errors.as_data())



            ret['message'] = obj.errors
            # 错误信息显示在页面上
            return HttpResponse(json.dumps(ret))
定义视图函数,调用form规则验证

前端ajax代码实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form id="fm" method="POST" action="/ajax/">
        {% csrf_token %}
        {{ obj.as_p }}
        <input type="button" value="Ajax提交" id="btn" />
    </form>
    <script src="/static/jquery-3.1.1.js"></script>
    <script>
        $(function () {
            $('#btn').click(function () {
                $.ajax({
                    url: '/ajax/',
                    type: 'POST',
                    data: $('#fm').serialize(),
                    dataType: 'JSON',
                    success:function (arg) {

                        // arg: 状态,错误信息
                        if (arg.status == ''){
                            window.location.href = "http://www.baidu.com"
                        }
                        console.log(arg);
                    }
                })
            })
        })
    </script>
</body>
</html>
ajax.html

7.2)对于数据库单字段验证验证

定义form规则,单字段验证

from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
class AjaxForm(forms.Form):
    username = fields.CharField()
    user_id = fields.IntegerField(
        widget=widgets.Select(choices=[(0,'alex'),(1,'刘皓宸'),(2,'杨建'),])
    )
    # 自定义方法 clean_字段名
    # 必须返回值self.cleaned_data['username']
    # 如果出错:raise ValidationError('用户名已存在')
    def clean_username(self):
        v = self.cleaned_data['username']
        if models.UserInfo.objects.filter(username=v).count():
            # 整体错了
            # 自己详细错误信息
            raise ValidationError('用户名已存在')
        return v
    def clean_user_id(self):
        return self.cleaned_data['user_id']
form规则唯一字段验证

 7.3)对于数据库多字段的唯一验证

from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
class AjaxForm(forms.Form):
    username = fields.CharField()
    user_id = fields.IntegerField(
        widget=widgets.Select(choices=[(0,'alex'),(1,'刘皓宸'),(2,'杨建'),])
    )
    # 自定义方法 clean_字段名
    # 必须返回值self.cleaned_data['username']
    # 如果出错:raise ValidationError('用户名已存在')
    def clean_username(self):
        v = self.cleaned_data['username']
        if models.UserInfo.objects.filter(username=v).count():
            # 整体错了
            # 自己详细错误信息
            raise ValidationError('用户名已存在')
        return v
    def clean_user_id(self):
        return self.cleaned_data['user_id']

    def clean(self):
        value_dict = self.cleaned_data
        v1 = value_dict.get('username')
        v2 = value_dict.get('user_id')
        if v1 == 'root' and v2==1:
                        raise ValidationError('整体错误信息')
                    return self.cleaned_data
多字段唯一验证

form表单系列原文出处:http://www.cnblogs.com/wupeiqi/articles/6144178.html

Model操作补充:http://www.cnblogs.com/wupeiqi/articles/6216618.html
Ajax全套: http://www.cnblogs.com/wupeiqi/articles/5703697.html

猜你喜欢

转载自www.cnblogs.com/linu/p/9557408.html