基于jQuery的Ajax实现(重点)

  • 异步提交
  • 局部刷新
"""

案例:github注册示例,
	动态获取用户名,实时的跟后端确认并实时展示到前端(局部刷新)

发送请求方式 
	1 浏览器地址栏直接输入url回车     GET请求
	2 a标签href属性				   GET请求
	3 form表单					POST请求/GET请求
	4 ajax						 POST请求/GET请求
	
"""

1、简介

AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。

AJAX 不是新的编程语言,而是一种使用现有标准的新方法。

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

AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。

  • 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
  • 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
Ajax只学习jQuery封装好之后的版本,所以在前端页面使用ajax的时候需要确保导入jQuery

2、Ajax语法

案例引入:

"""
页面有三个input框
    在前两个框中输入数字,点击按钮,朝后端发送到ajax请求
    后端计算出结果,再返回给前端动态展示到第三个input框
    (整个过程不允许有刷新,也不能再前端计算)

"""
# index.html

<body>
<input type="text" id="d1">+
<input type="text" id="d2">=
<input type="text" id="d3">
<p>
    <button id="btn">Click</button>
</p>
<script>
    //给按钮绑定点击事件
    $('#btn').click(function () {
        //朝后端发送ajax请求
        $.ajax({

            //1 指定朝哪个后端发送ajax请求
            url: '',//不写朝当前地址提交,跟action三种书写方式一致
            //2 请求方式
            type: 'post',//不指定,默认就是get
            //3 数据
            data: {'d1': $('#d1').val(), 'd2': $('#d2').val()},
            //4 回调函数:当后端给你返回结果的时候会自动触发 args接收后端的返回结果
            datatyp: 'JSON', //会自动反序列化
            success: function (args) {
                $('#d3').val(args)//通过DOM操作,动态渲染到第三个Input框
                #console.log(typeof (args))
                
            }
        })


    })
</script>
</body>

"""
针对后端,如果是用HttpResponse返回的json数据,前端回调函数不会自动反序列化,
如果后端直接用的JsonResponse返回的数据,回调函数会自动反序列化


HttpResponse解决方式
	1 自己再前端用JSON.parse()
	2.在ajax里配置一个参数
		dataType:'JSON'  
    """

当利用ajax进行前后端交互的时候,后端无论返回什么,都只会被回调函数接收,而不再影响这个浏览器页面

# views.py

from django.shortcuts import render, HttpResponse

from django.http import JsonResponse

# Create your views here.
def ab_ajax(request):
    if request.method == 'POST':
        # print(request.POST)
        # d1 = request.POST.get('d1')
        # d2 = request.POST.get('d2')
        # # 先转成整型
        # d3 = int(d1) + int(d2)
        # print(d3)
        d={'code':100,'msg':666}
        # return HttpResponse(d3)
        # return HttpResponse(json.dumps(d))
        return HttpResponse(JsonResponse(d))
    return render(request, 'index.html')
# urls.py

from django.contrib import admin
from django.urls import path
from app01 import  views
urlpatterns = [
    path('admin/', admin.site.urls),
    #ajax相关
    path('ab_ajax/',views.ab_ajax)
]

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

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

"""
get请求数据就是直接放在url后面的  
	url?username=zhao&password=123
"""

#可以朝后端发送post的请求方式
	"""
	1. form表单
	2. Ajax请求
	"""
    
# 前后端传输数据的编码格式
	"""
	urlencoded
	fromdata
	json
	"""

3.0、代码

# index.html

<form action="" method="post" >
    <p>username:<input type="text" name="username" id="" class="form-control"></p>
    <p>password:<input type="text" name="password" id="" class="form-control"></p>
    <p>file:<input type="file" name="file" id=""></p>
    <input type="submit" name="" id="" class="btn btn-primary">
    <input type="button" name="" id="d1" class="btn btn-danger" value="click">
</form>


<script>
    $('#d1').click(function (){
        $.ajax({
            utl:'',
            type:'post',
            data:{'username':'tony','age':19},
            success:function (args){

        }
        })
    })
</script>
# views.py

from django.shortcuts import render
# Create your views here.
def index(request):
    if request.method =='POST':
        print(request.POST)
        print(request.FILES)
    return render(request,'index.html')
# urls.py 

from django.contrib import admin
from django.urls import path
from app01 import  views
urlpatterns = [
    path('admin/', admin.site.urls),
    #前后端编码格式研究
    path('index/',views.index)
]

3.1、form表单

默认的编码格式是urlencoded
数据格式:username=zhao&password=123
django后端针对符合urlencoded编码格式的数据会自动的帮你解析封装到request.POST中
	username=zhao&password=123  >>> request.POST
   
如果把编码格式改成formdata,那么针对普通的键值对还是解析到request.POST中而将文件解析到request.FILES中


form表单没有办法发送json格式
  • 默认的编码格式

image-20221102200546457

  • 数据格式

image-20221102201124294

image-20221102201322322

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

image-20221102202334553

image-20221102203015897

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

image-20221102202407309

image-20221102202618109

image-20221102202655337

3.2、ajax

默认编码格式也是urlencoded
数据格式也是:username=tony&age=19
django后端针对符合urlencoded编码格式的数据会自动的帮你解析封装到request.POST中
	username=zhao&password=123  >>> request.POST

image-20221102204855809

  • 编码格式

image-20221102203718139

  • 数据格式

image-20221102203825877

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

image-20221102204038587

4、ajax发送json格式数据

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

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


"""

request对象补充
	request.is_ajax()
	判断当前请求是否是ajax请求,返回布尔值
    
django对json格式的数据不会做任何的处理

代码:

<!--ab_json.html-->

<body>
<button class="btn btn-danger" id="d1">click me !!</button>

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


            }
        })
    })
</script>
</body>
# views.py

def ab_json(request):
    # print(request.is_ajax())  # 判断当前请求是否是ajax请求,返回布尔值
    if request.is_ajax():
        # print(request.POST)
        # print(request.body)
        # 针对json格式数据需要自己手动处理
        json_bytes = request.body  # 二进制数据
        # json_str = json_bytes.decode('utf-8')  # 将二进制转成字符串
        # json_dic = json.loads(json_str)
        """json.loads括号内如果传入了一个二进制数据,那么内部可以自动解码再反序列化"""
        json_dic = json.loads(json_bytes)
        print(json_dic, type(json_dic))

    return render(request, 'ab_json.html')
# urls.py

from django.contrib import admin
from django.urls import path
from app01 import  views
urlpatterns = [
    path('admin/', admin.site.urls),

    #ajax发送json格式的数据
    path('ab_json/',views.ab_json)
]

ajax发送json格式数据需要注意以下几点

  1. contentType参数指定成application/json
  2. 确保是真正的json格式数据,JSON.stringify()
  3. django后端不会自动处理json格式,需要去request.body中获取数据并处理

  • 指定编码格式

image-20221102205741523

image-20221102205908090

  • 但是此时要发送的数据并不是json格式,需要转成json格式
  • 前端使用JSON.stringify()将想要发送的数据转成json格式的数据
data: JSON.stringify({'username': 'zhao', 'age': 19}),

image-20221102210141395

  • 查看json格式数据
{"username":"zhao","age":19}

image-20221102210354092

  • request.POST中找不到数据

image-20221102210714716

  • request.body中获取数据,转成json格式

image-20221103171457707

json.loads() 括号内如果传入了一个二进制数据,那么内部可以 自动解码再反序列化

image-20221102213336984

5、ajax发送文件数据

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

<p>username:<input type="text" id="d1"></p>
<p>password:<input type="text" id="d2"></p>
<p><input type="file" id="d3"></p>
<button class="btn btn-info" id="d4">Click Me !!!</button>


<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>
# views.py

def ab_file(request):
    if request.is_ajax():
        if request.method == 'POST':
            print(request.POST)
            print(request.FILES)
    return render(request, 'ab_file.html')

# urls.py

from django.contrib import admin
from django.urls import path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),

    # ajax发送文件
    path('ab_file/', views.ab_file),
]

image-20221102221448232

总结:

  1. ajax发文件需要利用内置对象FormData
       let formDataObj = new FormData();
        //2. 添加普通的键值对
        formDataObj.append('username', $('#d1').val());
        formDataObj.append('password', $('#d2').val());
        //3. 添加文件对象
        formDataObj.append('myfile', $('#d3')[0].files[0])
  1. 需要指定两个关键性参数
contentType: false, //不需要使用任何编码,django后端能自动识别formdata对象
processData: false, //告诉浏览器不要对数据进行任何处理
  1. django后端能自动识别FormData对象,能够将内部的普通键值自动封装到request.POST中,文件数据能自动解析封装request.FILES

6、Ajax结合sweetalert实现删除按钮的二次确认

<style>
        div.sweet-alert h2 {
            padding-top: 15px;
        }
</style>


<h1 class="text-center">数据展示</h1>
<table class="table table-hover table-striped">
    <thead>
    <tr>
        <th>ID</th>
        <th>username</th>
        <th>age</th>
        <th>gender</th>
        <th>describe</th>
    </tr>
    </thead>
    <tbody>
    {% for user_obj in user_queryset %}
        <tr>
            <td>{{ user_obj.pk }}</td>
            <td>{{ user_obj.age }}</td>
            <td>{{ user_obj.username }}</td>
            <td>{{ user_obj.gender }}</td>
            <td>
                <button class="btn btn-toolbar btn-xs">编辑</button>
                <!--注意,绑定ajax事件在for循环中不能加id,每for循环一次出现一个按钮,
                  如果绑定id就意味着for循环后出现的按钮id值一致,使用class=del
                    我们需要实现用户点击删除按钮,后端能够知道用户到底要删那条数据,
                    后端怎么知道?主键。
                   自定义属性

                   ----->

                <button class="btn btn-danger btn-xs del" delete_id="{{ user_obj.pk }}">删除</button>
            </td>

        </tr>
    {% endfor %}

    </tbody>
</table>


<script>
    $('.del').on('click', function () {
        //先将当前标签对象存储,用变量指代当前被点击对象
        let currentBtn = $(this);
        //二次确认弹框
        swal({
                title: "确定删除??",
                text: "确定要删吗!!!",
                type: "warning",
                showCancelButton: true,    //延时效果
                confirmButtonClass: "btn-danger",
                confirmButtonText: "我就要删!",
                cancelButtonText: "算了 算了 不删了",
                closeOnConfirm: false,
                closeOnCancel: false
            },
            //isConfirm 判断用户有没有点击二次确认删除按钮
            function (isConfirm) {
                if (isConfirm) {
                    // 朝后端发送ajax请求删除数据之后,后端判断是否有数据,再谈下面的提示框,
                    $.ajax({
                        // 向当前页面发送ajax请求,并携带需要产出数据的主键值,传递主键值第一种方式
                        {#url:'/delete/user/' + currentBtn.attr('delete_id'),#}
                        // 传递主键值第二种方式,放在请求体中
                        url: '/delete/user',
                        type: 'post',
                        data: {'delete_id': currentBtn.attr('delete_id')},
                        success: function (args) {
                            //判断响应状态码做不同的处理。
                            if (args.code === 1000) {
                                swal("已删除!", args.msg, "success");
                                // 2.利用DOM操作,动态刷新
                                // 当前端点击删除,后端找到标签所在行,通过DOM操作删除此行,
                                // delete_id 上一个标签是td,再上一个标签为tr,需要删的是当前标签delete_id所在的这一行。

                                // currentBtn指代的是当前被操作对象,parent()拿到父标签,两个parent()拿到父标签的父标签
                                currentBtn.parent().parent().remove()  //实时刷新
                            } else {
                                swal("出现问题", "..", "info");
                            }
                        }
                    })

                } else {
                    swal("您已取消", "...........", "error");
                }
            });
    })
</script>
# views.py

def delete_user(request):
    """
    前后端在使用ajax进行交互的时候,后端通常给ajax回调函数返回一个字典格式的数据
    字典返回到前端就是一个自定义对象,前端可以通过.的方式拿到想要的数据
    :param request:
    :return:
    """
    if request.is_ajax():
        if request.method == 'POST':
            # code:1000 为响应状态码
            back_dic = {'code': 1000, 'msg': ''}
            # 取到前端返回用户想要删除数据的主键值
            delete_id = request.POST.get('delete_id')
            models.User.objects.filter(pk=delete_id).delete()
            back_dic['msg'] = '数据已删除'
            # 需要告诉前端操作的结果
            return JsonResponse(back_dic)

效果图:

image-20221104224139637

(drf:django rest framework)