Ajax简介

文章详细阐述了Ajax在前端局部刷新中的应用,包括通过jQuery发送POST请求,处理数据编码格式,如urlencoded、formdata和json,以及如何处理响应。还讨论了文件上传和分页器的实现,并提到了Django中与Ajax交互的注意事项和数据校验。此外,文中还介绍了自定义分页器和forms组件在数据校验和前端渲染中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异步提交 局部刷新

        例子:github注册

                动态获取用户名实时的跟后端确认并实时展示的前端(局部刷新)

朝后端发送请求的方式

        1. 浏览器地址栏直接输入url回车        GET请求

        2. a标签href属性                                GET请求

        3. form表单                                        GET请求/POST请求

        4. ajax                                                GET请求/POST请求

Ajax 不是新的编程语言,而是一种使用现有标准的新方法 (比较装饰器)

Ajax 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容(这一特点给用户的感受是在不知不觉中完成请求和响应过程)

Ajax 只学习jQuery封装之后的版本 (原生的复杂并且在实际项目中也一般不用)

在前端页面使用ajax的时候需要确保导入了jQuery

ps: 并不只有jQuery能够实现Ajax, 其他的框架也可以 但是换汤不换药 原理是一样的

小例子

页面上有3个input框

        在前两个框中输入数字  点击按钮   朝后端发送ajax请求

        后端计算出结果  再返回给前端  动态展示到第3个input框中

        (整个过程页面不能刷新,也不能在前端计算)

    $('#btn').click(function(){
        // 朝后端发送ajax请求
        $.ajax({
            // 1. 指定朝哪个后端发送ajax请求
            url:'',// 不写就是朝当前地址提交
            // 2. 请求方式
            type:'post', // 不指定默认就是get 都是小写
            // 3. 数据
            {#data: {'username':'jason','password':123},#}
            data: {'d1':$('#d1').val(),'d2':$('#d2').val()},
            {#dataType:JSON, //会自动帮你反序列化#}

            // 4. 回调函数(异步回调机制): 当后端给你返回结果的时候会自动触发 args形参就是用来接收后端的返回结果
            success: function (args) {
                {#alert(args) // 通过DOM操作动态渲染到第3个input框里面#}
                {#$('#d3').val(args)#}
                {#console.log(typeof JSON.parse(args))#}
                {#$('#d3').val(JSON.parse(args).msg)#}
                console.log(typeof args)
                console.log(args.code)
                console.log(args.msg)
                $('#d3').val(args.msg)
            }


        })
    })

针对后端如果是用HttpResponse返回的数据 回调函数不会自动帮你反序列化

如果后端直接用的是JsonResponse返回的数据 糊掉函数会自动帮你反序列化

HttpResponse解决方式:

        1. 自己在前端利用JSON.parse()

        2. 在ajax里面配置一个参数 dataType:'json'

前后端传输数据的编码格式(contentType)

主要研究post请求数据的编码格式

get请求数据就是放在url后面的

url?username = jason & password = 123

可以朝后端发送post请求的方式

        1. form表单

        2. ajax请求

前后端传输数据的编码格式

        urlencoded

        

        formdata

        

        json

研究form表单

        默认的数据编码格式是urlencoded

        数据格式:username=jeffrey&password=123

        django后端针对符合urlencoded编码格式的数据都会自动帮你解析封装到request.POST中

        username=jeffrey&password=123&file=BOAM_O%26M_UI_LT_+Meeting_2023_wk2.pptx => request.POST

        如果你把编码格式改为formdata,那么针对普通的键值对还是解析到request.POST中而将文件解析到request.FILES中

        form表单是没有办法发送json格式数据的

研究ajax

         默认的数据编码格式也是urlencoded

        数据格式: username=jason&age=20

ajax发送json格式数据

前后端传输数据的时候一定要确保编码格式跟数据真正的格式是一致的

{"username":"jason","age":25}

        在request.POST里肯定找不到

        django针对json格式的数据        不会做任何的处理

request对象方法补充

        request.is_ajax()

        判断当前请求是否是ajax请求 返回布尔值

    <script>
        $('#d1').click(function (){
            $.ajax({
                url:'',
                type:'post',
                data:JSON.stringify({'username':'jason','age':25}),
                contentType:'application/json', //指定编码格式
                success:function(){

                }
            })
        })
    </script>
        json_bytes = request.body
        # json_str = json_bytes.decode('utf-8')
        # print(json_str,type(json_str))
        # json_dict = json.loads(json_str)
        # print(json_dict,type(json_dict))
        # json.loads括号内如果传入了一个二进制格式的数据,那么内部可以自动解码再反序列化
        json_dict = json.loads(json_bytes)
        print(json_dict,type(json_dict))

ajax 发送json格式数据需要注意的点

        1. contentType参数指定成: application/json

        2. 数据是真正的json格式数据

        3. django后端不会帮你处理json格式数据,需要你自己去request.body获取并处理

ajax发送文件

 ajax发送文件需要借助于js内置对象FormData

<script>
    // 点击按钮朝后端发送普通键值对和文件数据
    $('#d4').on('click',function (){
        // 1 需要先利用FormData内置对象
        let formDataObj = new FormData()
        // 2 添加普通的键值对
        formDataObj.append('username',$('#d1').val())
        formDataObj.append('password',$('#d2').val())
        // 3 添加文件对象
        formDataObj.append('myfile',$('#d3')[0].files[0])
        // 4 将对象基于ajax发送给后端
        $.ajax({
            url:'',
            type:'post',
            data:formDataObj, // 直接将对象放在data后面即可
            // ajax发送文件必须要指定的两个参数
            contentType: false, // 不需使用任何编码 django后端能够自动识别formdata对象
            processData: false, // 告诉浏览器不要对你的数据进行任何处理
            success:function(args){

            }
        })
    })
</script>
def ab_file(request):
    if request.is_ajax():
        if request.method == 'POST':
            print(request.POST)
            print(request.FILES)
    return render(request,'ab_file.html')

 总结:

        1 需要先利用FormData内置对象
        let formDataObj = new FormData()
        2 添加普通的键值对
        formDataObj.append('username',$('#d1').val())
        formDataObj.append('password',$('#d2').val())
        3 添加文件对象
        formDataObj.append('myfile',$('#d3')[0].files[0])
        4. 将对象基于ajax发送给后端, 需要指定两个关键性的参数
        $.ajax({
            url:'',
            type:'post',
            data:formDataObj, // 直接将对象放在data后面即可
            // ajax发送文件必须要指定的两个参数
            contentType: false, // 不需使用任何编码 django后端能够自动识别formdata对象
            processData: false, // 告诉浏览器不要对你的数据进行任何处理

            success:function(args){            }
             })
             })
             </script>

        5. django后端能够直接识别formdata对象并且能够将内部的普通键值自动解析并封装到request.POST中 文件数据自动解  析并封装到request.Files中

django自带的序列化组件 

如果发现可以使用MySQL但是无法使用sqlite3

只需要按照之前 MySQL的操作将sqlite3的驱动装一下即可

需求:在前端获取到后端用户表里面所有的数据 并且要是列表套字典

ajax结合sweetalert

如果拷贝sweetalert

基于别人的基础之上做修改

研究各个参数表示的意思 然后照葫芦画瓢

<script>
    $('.del').on('click', function () {
        // 先将当前标签对象存储起来
        let currentBtn = $(this)
        console.log($(currentBtn))
        {#alert(currentBtn.attr())#}
        {#console.log($(this).attr('delete_id'))#}
        {#alert($(this).attr('delete_id'))#}
        // 二次确认弹框
        swal({
                title: "你确定要删吗?",
                text: "你可要考虑清楚哦,可能需要拎包跑路哦!",
                type: "warning",
                showCancelButton: true,
                confirmButtonClass: "btn-danger",
                confirmButtonText: "是的,老子就要删",
                cancelButtonText: "算了,算了!",
                closeOnConfirm: false,
                closeOnCancel: false,
              showLoaderOnConfirm: true

            },
            function (isConfirm) {
                if (isConfirm) {
                    // 朝后端发送ajax请求删除数据之后再弹下面的提示框
                    $.ajax({
                        {#url:'/delete/user/' + currentBtn.attr('delete_id'), //传递主键值方式1#}
                        url: '/delete/user', //2 放在请求体里面
                        type: 'post',
                        data: {'delete_id': currentBtn.attr('delete_id')},
                        success: function (args) { //args = {'code':1000,'msg':''}
                            //判断响应状态码,然后做不同的处理
                            if (args.code === 1000) {
                                swal("删了!", args.msg, "success");
                                //1. lowb版本 直接刷新当前页面
                                {#window.location.reload()#}
                                //2. 利用DOM操作    动态刷新
                                currentBtn.parent().parent().remove()

                            }
                            else{
                                swal('完了','出现了未知的错误','info')
                            }

                        }

                    })
                } else {
                    swal("怂逼", "不要说我认识你", "error");
                }
            });
    })
</script>

批量插入

def ab_pl(request):
    # 先给Book表插入一万条数据
    # for i in range(1000):
    #     models.Book.objects.create(title='第%s本书'%i)
    # 再将所有的数据查询并展示到前端页面
    # 批量插入
    book_obj_list = []
    for i in range(10000):
        book_obj = models.Book(title='第%s本书'%i)
        book_obj_list.append(book_obj)
    models.Book.objects.bulk_create(book_obj_list)
    book_query = models.Book.objects.all()
    """
    当你使用批量插入数据的时候 使用orm给你提供的bulk_create可以大大节省时间
    """
    return render(request,'ab_pl.html',locals())

分页器

总数据100 每页展示10 需要10页

总数据101 每页展示10 需要11页

总数据99 每页展示10 需要10页

如何通过代码动态的计算出到底需要多少页?

在制作页码个数的时候 一般情况下都是奇数个 符合对称美的标准

def ab_pl(request):
    # 先给Book表插入一万条数据
    # for i in range(1000):
    #     models.Book.objects.create(title='第%s本书'%i)
    # 再将所有的数据查询并展示到前端页面
    # 批量插入
    # book_obj_list = []
    # for i in range(10000):
    #     book_obj = models.Book(title='第%s本书'%i)
    #     book_obj_list.append(book_obj)
    # models.Book.objects.bulk_create(book_obj_list)
    # book_query = models.Book.objects.all()
    # book_query = models.Book.objects.all()
    """
    当你使用批量插入数据的时候 使用orm给你提供的bulk_create可以大大节省时间
    """
    print(request.GET)
    book_list = models.Book.objects.all()

    # 想访问哪一页
    current_page = request.GET.get('page',1) # 如果获取不到当前页码 就展示第一页
    # 数据类型转换
    try:
        current_page = int(current_page)
    except Exception as e:
        current_page = 1
    # 每页展示多少条
    per_page_num = 10
    # 计算出到底需要多少页
    all_count = book_list.count()
    page_count, more = divmod(all_count,per_page_num)
    if more:
        page_count +=1
    # print(current_page)
    page_html = ''
    # 起始位置
    start_page = (current_page - 1) * per_page_num
    # 终止位置
    end_page = current_page * per_page_num
    xxx = current_page
    if current_page < 6:
        current_page = 6
    for i in range(current_page-5,current_page+6):
        if xxx  == i:
            page_html += '<li class="active"><a href="?page=%s">%s</a></li>'%(i,i)
        else:
            page_html += '<li><a href="?page=%s">%s</a></li>'% (i, i)



    book_query = book_list[start_page:end_page]


    return render(request,'ab_pl.html',locals())

django中有自带的分页器模块        但是书写起来很麻烦并且功能太简单

自定义分页器的拷贝及使用

当我们需要使用到非django内置的第三方功能或者组件代码的时候

我们一般情况下会创建一个名为utils的文件夹         在该文件夹内对模块进行功能性划分

        utils可以在每个应用下创建,也可以在全局创建

我们到了后期封装代码的时候        不再局限于函数

尽量用面向对象的方式去封装

后端

def book_list(request):
    # print('request.get:',request.GET)
    # current_page = request.GET.get('page',1)
    # print('current_page:',current_page)
    # print(type(current_page))
    # number_per_page = 10
    #
    # book_list = models.Book.objects.all()
    # start = (int(current_page) -1) * number_per_page
    # end = int(current_page) *number_per_page
    # print('start,end',start,end)
    # book_queryset = book_list[start:end]
    # print(book_queryset)
    # # book_queryset = book_list[(int(current_page)-1)*number_per_page,int(current_page)*number_per_page]
    # # book_queryset = book_list[(current_page)-1*number_per_page,current_page*number_per_page]
    # # print(book_list[20:30])
    # count = book_list.count()
    # print('count',count)
    # page, left = divmod(count, number_per_page)
    # print('page',page)
    # print('left',left)
    # if left > 0:
    #     left =1
    # total_page = page + left
    #
    # page_html = ''
    # tmp = int(current_page)
    # if int(current_page) <6:
    #     current_page = 6
    # elif total_page - int(current_page) <5:
    #     current_page = total_page -5
    # for i in range(int(current_page)-5,int(current_page)+6):
    #     # print('i:',i)
    #     if tmp == i:
    #         page_html += '<li class="active"><a href="?page={}">{}</a></li>'.format(i, i)
    #     # elif tmp == total_page:
    #     #     page_html += '<li class="active"><a href="?page={}">{}</a></li>'.format(i,i)
    #     else:
    #         page_html += '<li><a href="?page={}">{}</a></li>'.format(i, i)
    #
    # print(page_html)
    #
    #
    #
    # print('total_page',total_page)
    # if request.is_ajax():
    #     if request.method == 'POST':
    #         back_end = {'code':1000,'msg':''}
    #         delete_id = request.POST.get('delete_id')
    #         # print('delete_id:',delete_id)
    #         res = models.Book.objects.filter(pk=delete_id).delete()
    #         # print('res:',res)
    #         back_end['msg'] = '删除成功'
    #         # print(back_end)
    #         return JsonResponse(back_end)
    current_page = request.GET.get('page',1)
    all_count = models.Book.objects.all().count()
    # 1. 实例化 传值生成对象
    page_obj = Pagination(current_page=current_page,all_count=all_count)
    # 2. 直接对总数据进行切片操作
    # print(page_obj.start)
    # print(page_obj.end)
    # print(type(page_obj.end))
    page_queryset = models.Book.objects.all()[page_obj.start:page_obj.end]
    # 3. 将page_queryset传递到页面 替换之前的book_queryset
    return render(request,'book_list.html',locals())

前端

<body>
<h1 class="text-center">图书列表</h1>
<div class="container-fluid">
    <div class="row">
        <div class="col-md-offset-2 col-md-8">
            <table class="table table-hover table-striped table-striped table-bordered">
                <thead>
                <tr>
                    <td>ID</td>
                    <td>书名</td>
                    <td>价格</td>
                    <td>操作</td>
                </tr>
                </thead>
                <tbody>
                {% for book_obj in page_queryset %}
                    <tr>
                    <td>{{ book_obj.pk }}</td>
                    <td>{{ book_obj.title }}</td>
                    <td>{{ book_obj.price }}</td>
                    </tr>
                {% endfor %}
                                </tbody>
            </table>
                {{ page_obj.page_html|safe }}
{#                {% for book_obj in book_queryset %}#}
{#                    <tr>#}
{#                        <td>{{ book_obj.pk }}</td>#}
{#                        <td>{{ book_obj.title }}</td>#}
{#                        <td>{{ book_obj.price }}</td>#}
{#                        <td>#}
{#                            <a href="/bookupdate/{{ book_obj.pk }}" class="btn btn-primary">修改</a>#}
{#                            <button class="btn btn-danger btn_delete" delete_id="{{ book_obj.pk }}">删除</button>#}
{#                        </td>#}
{#                    </tr>#}
{#                {% endfor %}#}


{#            <nav aria-label="Page navigation">#}
{#                <ul class="pagination">#}
{#                    <li>#}
{#                        <a href="#" aria-label="Previous">#}
{#                            <span aria-hidden="true">&laquo;</span>#}
{#                        </a>#}
{#                    </li>#}
{#                    {{ page_html|safe }}#}
{#                    <li class="active"><a href="#">1</a></li>#}
{#                    <li><a href="#">2</a></li>#}
{#                    <li><a href="#">3</a></li>#}
{#                    <li><a href="#">4</a></li>#}
{#                    <li><a href="#">5</a></li>#}
{#                    <li>#}
{#                        <a href="#" aria-label="Next">#}
{#                            <span aria-hidden="true">&raquo;</span>#}
{#                        </a>#}
{#                    </li>#}
{#                </ul>#}
{#            </nav>#}
        </div>
    </div>
</div>
<script>
    $('.btn_delete').on('click', function () {
        let currentBtn = $(this)
        console.log(currentBtn.attr('delete_id'))
        swal({
                title: "确定要删除吗?",
                text: "删除很严重哦!",
                type: "warning",
                showCancelButton: true,
                confirmButtonClass: "btn-danger",
                confirmButtonText: "是的,删吧删吧!",
                cancelButtonText: "算了,还是算了吧!",
                closeOnConfirm: false,
                closeOnCancel: false
            },
            function (isConfirm) {
                if (isConfirm) {
                    $.ajax({
                        url: '',
                        type: 'post',
                        {#contentType:'application:json',#}
                        data: {'delete_id': currentBtn.attr('delete_id')},
                        success: function (args) {
                            {#alert(args)#}
                            console.log(args)
                        }
                    })
                    swal("删除成功!", "可以跑路啦", "success");
                    currentBtn.parent().parent().remove()
                } else {
                    swal("取消啦", "你个怂逼", "error");
                }
            });

    })
</script>
</body>

form组件前戏

写一个注册功能

        获取用户民和密码 利用form表单提交数据

        在后端判断用户名和密码是否符合一定的条件

                用户名中不能含有金瓶梅

                密码不能少于三位

        如果不符合条件需要你将提示信息展示到前端页面

def ab_form(request):
    back_dic = {'username':'','password':''}
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if '金瓶梅' in username:
            back_dic['username'] = '不符合社会主义核心价值观'
        if len(password) <3 :
            back_dic['password'] = '不能太短 不好'
    """
    无论是post请求还是ge请求
    页面都能获取到字典 只不过get请求来的时候 字典值都是空的
    而post请求来之后 字典可能有值
    """
    return render(request,'ab_form.html',locals())
<form action="" method="post">
    <p>username:
        <input type="text" name="username">
        <span style="color: red">{{ back_dic.username }}</span>
    </p>
    <p>password:
        <input type="text" name="password">
        <span style="color: red">{{ back_dic.password }}</span>
    </p>
    <input type="submit" class="btn btn-info">
</form>

1. 手动书前端获取用户的html代码        渲染html代码

2. 后端对用户数据进行校验                校验数据

3. 对不符合要求的数据进行前端提示        展示提示信息

forms组件

    能够完成的事情
            1.渲染html代码
            2.校验数据
            3.展示提示信息

为什么数据校验非要去后端 不能在前端利用js直接完成呢?
    数据校验前端可有可无
    但是后端必须要有!!!
    
    因为前端的校验是弱不禁风的 你可以直接修改
    或者利用爬虫程序绕过前端页面直接朝后端提交数据
    
    购物网站    
        选取了货物之后 会计算一个价格发送给后端 如果后端不做价格的校验
        
        实际是获取到用户选择的所有商品的主键值
        然后在后端查询出所有商品的价格 再次计算一遍
        如果跟前端一致 那么完成支付如果不一致直接拒绝

基本使用

from django import forms

class MyForm(forms.Form):
    # username字符串类型最小3位最大8位
    username = forms.CharField(min_length=3,max_length=8)
    # password字符串类型最小3位最大8位
    password = forms.CharField(min_length=3,max_length=8)
    # email字段必须符合邮箱格式  xxx@xx.com
    email = forms.EmailField()

校验数据

"""
1.测试环境的准备 可以自己拷贝代码准备
2.其实在pycharm里面已经帮你准备一个测试环境
    python console
"""
 

from app01 import views
# 1 将带校验的数据组织成字典的形式传入即可
form_obj = views.MyForm({'username':'jason','password':'123','email':'123'})
# 2 判断数据是否合法        注意该方法只有在所有的数据全部合法的情况下才会返回True
form_obj.is_valid()
False
# 3 查看所有校验通过的数据
form_obj.cleaned_data
{'username': 'jason', 'password': '123'}
# 4 查看所有不符合校验规则以及不符合的原因
form_obj.errors
{
  'email': ['Enter a valid email address.']
}
# 5 校验数据只校验类中出现的字段 多传不影响 多传的字段直接忽略
form_obj = views.MyForm({'username':'jason','password':'123','email':'123@qq.com','hobby':'study'})
form_obj.is_valid()
True
# 6 校验数据 默认情况下 类里面所有的字段都必须传值
form_obj = views.MyForm({'username':'jason','password':'123'})
form_obj.is_valid()
False
"""
也就意味着校验数据的时候 默认情况下数据可以多传但是绝不可能少传
"""

渲染标签


forms组件只会自动帮你渲染获取用户输入的标签(input select radio checkbox)
不能帮你渲染提交按钮

def index(request):
    # 1 先产生一个空对象
    form_obj = MyForm()
    # 2 直接将该空对象传递给html页面
    return render(request,'index.html',locals())


 



# 前端利用空对象做操作
    <p>第一种渲染方式:代码书写极少,封装程度太高 不便于后续的扩展 一般情况下只在本地测试使用</p>
    {{ form_obj.as_p }}
    {{ form_obj.as_ul }}
    {{ form_obj.as_table }}
    <p>第二种渲染方式:可扩展性很强 但是需要书写的代码太多  一般情况下不用</p>
    <p>{{ form_obj.username.label }}:{{ form_obj.username }}</p>
    <p>{{ form_obj.password.label }}:{{ form_obj.password }}</p>
    <p>{{ form_obj.email.label }}:{{ form_obj.email }}</p>
    <p>第三种渲染方式(推荐使用):代码书写简单 并且扩展性也高</p>
    {% for form in form_obj %}
        <p>{{ form.label }}:{{ form }}</p>
    {% endfor %}
 
"""


label属性默认展示的是类中定义的字段首字母大写的形式
也可以自己修改 直接给字段对象加label属性即可
     username = forms.CharField(min_length=3,max_length=8,label='用户名')

展示提示信息

浏览器会自动帮你校验数据 但是前端的校验弱不禁风

如何让浏览器不做校验

def index(request):
    # 1.  先产生一个空对象
    form_obj = Myform()
    if request.method == 'POST':
        # 获取用户数据并校验
        """
        1. 数据获取繁琐
        2. 校验数据需要构造成字典的格式传入才行
        ps: 但是request.POST可以看成就是一个字典
        """
        #4. 判断数据是否合法
        form_obj = Myform(request.POST)
        if form_obj.is_valid():
            # 5. 如果合法 操作数据库存储数据
            return HttpResponse('OK')
        else:
            # 如何将错误信息展示到前端
            pass

    # 2. 直接将该空对象传递给html页面
    return render(request,'index.html',locals())
    {% for form in form_obj %}
        <p>{{ form.label }}:{{ form }}        <span style="color: red">{{ form.errors.0 }}</span></p>

    {% endfor %}

1. 必备的条件 get请求和post请求传给html页面的对象变量名必须一样

2. form组件当你的数据不合法的情况下 会保存你上次的数据 让你基于之前的结果进行修改 增加人性化

针对错误的提示信息还可以自己定制

class Myform(forms.Form):
    # username字符串类型最小3位,最大8位
    username = forms.CharField(min_length=3,max_length=8,label='用户名',error_messages={
        'min_length':'用户名最少3位',
        'max_length':'用户名最大8位',
        'required':'用户名不能为空',
    })
    # password字符串最小3位最大8位
    password = forms.CharField(min_length=3,max_length=8,label='密码',error_messages={
        'min_length':'密码最少3位',
        'max_length':'密码最大8位',
        'required':'密码不能为空',
    })
    # email字段必须符合邮箱格式
    email = forms.EmailField(label='邮箱',error_messages={
        # 'min_length':'用户名最少3位',
        # 'max_length':'用户名最大8位',
        'required':'邮箱不能为空',
        'invalid':'邮箱格式不正确',
    })

钩子函数(HOOK)

在特定的节点自动触发完成相应操作

钩子函数在forms组件中就类似于第二道关卡,能够让我们自定义校验规则

在forms组件中有两类钩子

        1. 局部钩子

                当你需要给单个字段增加校验规则的时候可以使用

        2. 全局钩子

                但你需要给多个字段增加校验规则的时候可以使用

 实际案例:

        1. 校验用户名中不能含有666        只是校验username字段        局部钩子

        2. 校验密码和确认密码是否一致        password和 cofirm 2个字段        全局钩子

在类里面书写方法即可

 # 钩子函数

    # 局部钩子
    def clean_username(self):
        # 获取到用户名
        username = self.cleaned_data.get('username')
        if '666' in username:
            # 提示前端展示错误信息
            self.add_error('username','光喊666是不行的~')
        # 将钩子函数钩取出来的数据再放回去
        return username

    # 全局钩子
    def clean(self):
        password = self.cleaned_data.get('password')
        confirm_password =self.cleaned_data.get('confirm_password')
        if not confirm_password == password:
            self.add_error('confirm_password','两次密码不一致')
        # 将钩子函数钩取出来的数据再放回去
        return self.cleaned_data

forms组件其他参数及补充知识点

label        字段名

error_messages 报错信息

initial  字段默认值

required 控制字段是否必填

"""

1. 字段没有样式

2. 针对不同类型的input如何修改

        text

        password

        date

        radio

        checkbox

widget=forms.widgets.PasswordInput(attrs={'class':'form-control'})

多个属性的话 直接空格隔开即可

forms组件源码

切入点:

        form_obj.is_valid()

    def is_valid(self):
        """Return True if the form has no errors, or False otherwise."""
        return self.is_bound and not self.errors

self.is_bound = data is not None or files is not None # 只要传值了肯定为True

    @property
    def errors(self):
        """Return an ErrorDict for the data provided for the form."""
        if self._errors is None:
            self.full_clean()
        return self._errors

# forms组件所有的功能基本都出自于该方法
def full_clean(self):
    self._clean_fields() # 校验字段 + 局部狗柜子
    self._clean_form() # 全局钩子
    self._post_clean()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值