django-ajax傳輸數據

AJAX簡介

AJAX(Asynchronous Javascript And XML)翻譯成中文就是「異步Javascript和XML」. 即便用Javascript語言與服務器進行異步交互,傳輸的數據爲XML(固然,傳輸的數據不僅是XML,如今更多使用json數據).javascript

AJAX的特色:css

異步交互: 客戶端發出一個請求後,無需等待服務器響應結束,就能夠發出第二個請求html

這裏穿插異步同步的概念:

同步: 線程提交任務後, 必須原地等待任務結果產生, 才能繼續執行下一行代碼
異步: 線程提交任務後, 無需等待結果的產生, 直接執行下一行代碼. 當結果產生後, 會觸發回調函數來處理結果.

局部刷新: 使用ajax與服務器進行數據交換後, 會經過js代碼進行dom操做進行局部的頁面替換, 不會刷新整個頁面. 所以ajax的性能也比較高.java

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發送的.python

JQuery實現AJAX

基本的實現流程:jquery

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, 能夠從瀏覽器的請求中看出ajax

下面將利用json來進行數據的交互django

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裏面讓咱們本身來處理.json

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數據類型相互轉換的結果.bootstrap

+---------------+-------------------+
| 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')

相關文章
相關標籤/搜索