• django-ajax传输数据


    AJAX简介

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

    AJAX的特点:

    异步交互: 客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求

    这里穿插异步同步的概念:
    
    同步: 线程提交任务后, 必须原地等待任务结果产生, 才能继续执行下一行代码
    异步: 线程提交任务后, 无需等待结果的产生, 直接执行下一行代码. 当结果产生后, 会触发回调函数来处理结果.
    

    局部刷新: 使用ajax与服务器进行数据交换后, 会通过js代码进行dom操作进行局部的页面替换, 不会刷新整个页面. 因此ajax的性能也比较高.

    JS实现AJAX

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    {% csrf_token %}
    <button id="id_js_button">原生js发送ajax请求</button>
    </body>
    <script>
        var b2 = document.getElementById("id_js_button");
        b2.onclick = function () {
            // 原生JS
            var xmlHttp = new XMLHttpRequest();
            xmlHttp.open("post", "/test_ajax/", true);
            xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            var csrf_token = document.getElementsByTagName('input')[0].value;
            console.log(csrf_token);
            xmlHttp.send("username=test&password=123456&csrfmiddlewaretoken=" + csrf_token);
            xmlHttp.onreadystatechange = function () {
                if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
                    alert(xmlHttp.responseText);
                }
            };
        };
    </script>
    </html>
    

    由于原生js发送ajax请求步骤太过麻烦与复杂, 下面发送的ajax请求都是基于jQuery发送的.

    JQuery实现AJAX

    基本的实现流程:

    contentType: urlencoded

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    </head>
    <body>
    {% csrf_token %}
    <button id="id_jQuery_button">jQuery发送ajax请求</button>
    </body>
    <script>
        $('#id_jQuery_button').click(function () {
            $.ajax({
                // url后面的参数表示需要提交的地址, 不写默认给当前地址提交
                url: '',
                // type表示提交的方式, get, post, application/json
                type: 'post',
                // data后面的参数是表示需要上传的数据
                data: {
                    'username': 'root', 'password': '123', 'csrfmiddlewaretoken': '{{csrf_token}}',
                },
                // success表示服务端给出响应后执行的回调函数
                // 数据传递给data接收
                success: function (data) {
                    console.log(data);
                }
            })
        })
    </script>
    </html
    

    上面虽然是基于ajax发送post请求的, 但是它的默认编码方式还是urlencoded, 可以从浏览器的请求中看出

    下面将利用json来进行数据的交互

    contentType: application/json

    <script>
        $('#id_jQuery_button').click(function () {
            var send_data = {
                'username': 'root',
                'password': '123',
            };
    
            $.ajax({
                // url后面的参数表示需要提交的地址, 不写默认给当前地址提交
                url: '',
                // type表示提交的方式, get, post, application/json
                type: 'post',
                // 发送post请求, 需要注意这里必须携带上这个参数, 否则会403错误
                headers: {
                    'X-CSRFTOKEN': '{{csrf_token}}'
                },
                //发送json数据格式的话, 需要改变contentType参数
                contentType: 'application/json',
                // data后面的参数是表示需要上传的数据
                data: JSON.stringify(send_data),
                // success表示服务端给出响应后执行的回调函数
                // 数据传递给data接收
                success: function (data) {
                    console.log(data);
                }
            })
        })
    </script>
    

    使用json传输数据需要注意的是, 后端处理的过程也有点不一样了. Django不会处理json数据, 而是把数据放在body里面让我们自己来处理.

    def test_ajax(request):
        if request.is_ajax():
            # 发送过来的如果是json字符串, Django不会帮我们来处理
            # 会将数据保存在body中, 需要我们自己处理
            print(request.body)
            import json
            print(json.loads(request.body, encoding='utf-8'))
            return JsonResponse({'code': 100, 'msg': '收到'})
    
        return render(request, 'ajax_test.html')
    
    # out:
    # b'{"username":"root","password":"123"}'
    # {'username': 'root', 'password': '123'}
    

    最后补充个json和Python数据类型相互转换的结果.

    +---------------+-------------------+
    | JSON          | Python            |
    +===============+===================+
    | object        | dict              |
    +---------------+-------------------+
    | array         | list              |
    +---------------+-------------------+
    | string        | str               |
    +---------------+-------------------+
    | number (int)  | int               |
    +---------------+-------------------+
    | number (real) | float             |
    +---------------+-------------------+
    | true          | True              |
    +---------------+-------------------+
    | false         | False             |
    +---------------+-------------------+
    | null          | None              |
    +---------------+-------------------+
    

    contentType: multipart/form-data;

    最后一种是利用ajax发送了form-data格式的数据.

    upload.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
        <title>Title</title>
    </head>
    <body>
    <div class="container">
        <div class="row">
            <div class="col-md-offset-2 col-md-8">
                <h2>ajax上传文件</h2>
                <hr>
                <form>
                    {% csrf_token %}
                    <div class="form-group">
                        <label for="InputFile">选择图片</label>
                        <span>
                            <label for="InputFile">
                                <img src="" alt="" width="200px" id="displayImg">
                            </label>
                            <input type="file" id="InputFile" style="display: none">
                        </span>
                    </div>
                    <button type="button" class="btn btn-default" id="submit">提交</button>
                </form>
            </div>
        </div>
    </div>
    </body>
    <script>
        // 把选择的图片渲染到上面.
        let imgReader = new FileReader();
        $('#InputFile').change(function () {
            // 从选择的文件读取内容
            let selectFile = $('#InputFile')[0].files[0];
            imgReader.readAsDataURL(selectFile);
            // 等待读取完全
            imgReader.onload = function () {
                // 将图片渲染到展示框
                $('#displayImg').attr('src', imgReader.result);
            };
        });
    
        $('#submit').on('click', function () {
            // 这里获取文件内容并上传
            let formData = new FormData();
            let selectFile = $('#InputFile')[0].files[0];
            formData.append('file', selectFile);
            formData.append('csrfmiddlewaretoken', '{{ csrf_token }}');
            $.ajax({
                url: '',
                type: "post",
                data: formData,
                // ajax上传文件一定要指定这两个参数
                contentType: false,
                processData: false,
                success: function (data) {
                    if (data.code === 100) {
                        alert('文件上传成功!');
                    } else {
                        alert('上传失败!')
                    }
                }
            })
        })
    </script>
    </html>
    

    view.py

    def upload(request):
        if request.method == 'POST' and request.is_ajax():
            # 获取文件信息
            print(request.FILES)
            # 读取文件保存到本地中
            file = request.FILES.get('file')
            with open(file.name, 'wb') as f:
                for chunk in file.chunks():
                    f.write(chunk)
            return JsonResponse({'code': 100})
        return render(request, 'upload.html', locals())
    

    上传文件使用FormData传输, Content-Type自动指定为form-data.

    传输csrf_token的其他方式

    上面几个例子, 都看出来了每次遇到post请求, 都需要我们手动传csrf_token参数, 这样非常麻烦, 因此我们可以更改jQuery的ajax传递方式, 在传输数据之前, 加入我们需要的csrf_token就可以了. 详细的信息参考Django官方文档

    方式1: 从cookie中获取

    注意:需要引入一个jquery.cookie.js插件。

    <script>
        $.ajax({
          url: "/cookie_ajax/",
          type: "POST",
          headers: {"X-CSRFToken": $.cookie('csrftoken')},  // 从Cookie取csrf_token,并设置ajax请求头
          data: {"username": "test", "password": 123456},
          success: function (data) {
            console.log(data);
          }
        })
    </script>
    

    方式2: 自己写一个getCookie方法

    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    var csrftoken = getCookie('csrftoken');
    

    方式3: 直接使用$.ajaxSetup()方法为ajax请求统一设置, 即在发送前设置csrftoken参数.

    function csrfSafeMethod(method) {
      // these HTTP methods do not require CSRF protection
      return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    
    $.ajaxSetup({
      beforeSend: function (xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
      }
    });
    

    注意: 上面这几种方式都是基于jQuery上解决的, 需要先引入jQuery文件, 才能生效.

    小练习

    写一个注册页面, 能够让用户将光标移开后能够显示用户名是否已被注册过, 将光标重新聚焦输入, 又会将错误信息清空.

    注册页面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
        <title>Title</title>
    </head>
    <body>
    
    <div class="container">
        <div class="row">
            <div class="col-md-offset-3 col-md-6">
                <h2>注册页面</h2>
                {% csrf_token %}
                <div class="form-group">
                    <label for="id_username">用户名</label>
                    <input type="text" class="form-control" name="username" id="id_username">
                    <span class="pull-right"></span>
                </div>
                <div class="form-group">
                    <label for="id_password">密码</label>
                    <input type="text" class="form-control" name="password" id="id_password">
                    <span class="pull-right"></span>
                </div>
                <div class="form-group">
                    <input type="button" class="btn btn-success" id="id_submit" value="提交">
                </div>
            </div>
        </div>
    </div>
    <script>
        $('#id_username').blur(function () {
            // 判断当用户用户名框移出, 就向服务器发送请求
            let username = $(this).val();
            let $username = $(this);
            $.ajax({
                url: '',
                type: 'post',
                data: {'username': username, 'csrfmiddlewaretoken': '{{ csrf_token }}'},
                success: function (data) {
                    if (data.code === 100){
                        $username.next().css('color', 'black').text('用户名可以使用').parent().addClass('has-success');
                    } else if (data.code === 101) {
                        $username.next().text('用户名不能为空').css('color', 'red').parent().addClass('has-error');
                    } else{
                        $username.next().text('用户名已存在').css('color', 'red').parent().addClass('has-error')
                    }
                }
            })
        }).focus(function () {
            $(this).next().text('').parent().removeClass('has-error');
        });
    </script>
    </body>
    </html>
    

    views.py

    def reg(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            back_dic = {'code': 100, 'msg': ''}
            if username in ['a', 'b', 'c']:
                back_dic['code'] = 102
                back_dic['msg'] = '用户名已存在'
            elif not username:
                back_dic['code'] = 101
                back_dic['msg'] = '用户名不能为空'
            else:
                back_dic['msg'] = '用户名可以使用'
            return JsonResponse(back_dic)
        return render(request, 'reg.html')
    

  • 相关阅读:
    【JAVA基础&Python】静态方法与单例模式,以及应用场景
    【JAVA基础】static的定义
    【JAVA基础&Python】类与对象的继承
    MD的编辑器汇总
    Oracle 学习笔记(二)
    安装Jieba 库出现错误解总结
    (十五)-前端 -项目总结
    (八)-前端-DOM基础
    (十四)-前端-面试-项目相关
    (十三)- 前端-面试-REACT
  • 原文地址:https://www.cnblogs.com/yscl/p/11610869.html
Copyright © 2020-2023  润新知