1. 程式人生 > 其它 >07 django與ajax

07 django與ajax

AJAX準備知識:JSON

什麼是 JSON ?

  • JSON 指的是 JavaScript 物件表示法(JavaScript Object Notation)

  • JSON 是輕量級的文字資料交換格式

  • JSON 獨立於語言 *

  • JSON 具有自我描述性,更易理解

* JSON 使用 JavaScript 語法來描述資料物件,但是 JSON 仍然獨立於語言和平臺。JSON 解析器和 JSON 庫支援許多不同的程式語言。

啥都別多說了,上圖吧!

合格的json物件(json只認雙引的字串格式):

["one", "two", "three"]
{ "one": 1, "two": 2, "three": 3 }
{"names": ["張三", "李四"] }
[ { "name": "張三"}, {"name": "李四"} ] 

不合格的json物件:

{ name: "張三", 'age': 32 }  // 屬性名必須使用雙引號
[32, 64, 128, 0xFFF] // 不能使用十六進位制值
{ "name": "張三", "age": undefined }  // 不能使用undefined
{ "name": "張三",
 "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'),
 "getName":  function() {return this.name;}  // 不能使用函式和日期物件
}

stringify與parse方法

JavaScript中關於JSON物件和字串轉換的兩個方法:

JSON.parse(): 用於將一個 JSON 字串轉換為 JavaScript 物件(json只認雙引的字串格式)

JSON.parse('{"name":"Howker"}');
JSON.parse('{name:"Stack"}') ;   // 錯誤
JSON.parse('[18,undefined]') ;   // 錯誤

JSON.stringify(): 用於將 JavaScript 值轉換為 JSON 字串。

JSON.stringify({"name":"Tonny"})

 

和XML的比較

JSON 格式於2001年由 Douglas Crockford 提出,目的就是取代繁瑣笨重的 XML 格式。

JSON 格式有兩個顯著的優點:書寫簡單,一目瞭然;符合 JavaScript 原生語法,可以由解釋引擎直接處理,不用另外新增解析程式碼。所以,JSON迅速被接受,已經成為各大網站交換資料的標準格式,並被寫入ECMAScript 5,成為標準的一部分。

XML和JSON都使用結構化方法來標記資料,下面來做一個簡單的比較。

用XML表示中國部分省市資料如下:

<?xml version="1.0" encoding="utf-8"?>
<country>
   <name>中國</name>
   <province>
       <name>黑龍江</name>
       <cities>
           <city>哈爾濱</city>
           <city>大慶</city>
       </cities>
   </province>
   <province>
       <name>廣東</name>
       <cities>
           <city>廣州</city>
           <city>深圳</city>
           <city>珠海</city>
       </cities>
   </province>
   <province>
       <name>臺灣</name>
       <cities>
           <city>臺北</city>
           <city>高雄</city>
       </cities>
   </province>
   <province>
       <name>新疆</name>
       <cities>
           <city>烏魯木齊</city>
       </cities>
   </province>
</country>

用JSON表示如下:

{
   "name": "中國",
   "province": [{
       "name": "黑龍江",
       "cities": {
           "city": ["哈爾濱", "大慶"]
      }
  }, {
       "name": "廣東",
       "cities": {
           "city": ["廣州", "深圳", "珠海"]
      }
  }, {
       "name": "臺灣",
       "cities": {
           "city": ["臺北", "高雄"]
      }
  }, {
       "name": "新疆",
       "cities": {
           "city": ["烏魯木齊"]
      }
  }]
}

由上面的兩端程式碼可以看出,JSON 簡單的語法格式和清晰的層次結構明顯要比 XML 容易閱讀,並且在資料交換方面,由於 JSON 所使用的字元要比 XML 少得多,可以大大得節約傳輸資料所佔用得頻寬。

AJAX簡介

AJAX(Asynchronous Javascript And XML)翻譯成中文就是“非同步的Javascript和XML”。即使用Javascript語言與伺服器進行非同步互動,傳輸的資料為XML(當然,傳輸的資料不只是XML)。

AJAX 不是新的程式語言,而是一種使用現有標準的新方法。

AJAX 最大的優點是在不重新載入整個頁面的情況下,可以與伺服器交換資料並更新部分網頁內容。(這一特點給使用者的感受是在不知不覺中完成請求和響應過程)

AJAX 不需要任何瀏覽器外掛,但需要使用者允許JavaScript在瀏覽器上執行。

  • 同步互動:客戶端發出一個請求後,需要等待伺服器響應結束後,才能發出第二個請求;

  • 非同步互動:客戶端發出一個請求後,無需等待伺服器響應結束,就可以發出第二個請求。

示例

*頁面輸入兩個整數,通過AJAX傳輸到後端計算出結果並返回。*

html部分程式碼

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>Title</title>
   <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<input type="text" id="i1"> + <input type="text" id="i2"> = <input type="text" id="i3">
<button id="b1">Ajax Test</button>

<script src="/static/jquery-3.3.1.min.js"></script>
<script>
   $('#b1').click(function () {
       $.ajax({
           url:'',
           type:'POST',
           data:{i1:$('#i1').val(),i2:$('#i2').val()},
           success:function (data) {
               $('#i3').val(data)
          }
      })
  })

</script>
</body>
</html>

views.py

def ajax_test(request):
   if request.method=='POST':
       i1=request.POST.get('i1')
       i2=request.POST.get('i2')
       ret=int(i1)+int(i2)
       return HttpResponse(ret)
   return render(request,'ajax_test.html')

urls.py

from django.conf.urls import url
from app01 import views
urlpatterns=[
    url(r'^ajax_test/',views.ajax_test),
]

AJAX常見應用情景

搜尋引擎根據使用者輸入的關鍵字,自動提示檢索關鍵字。

還有一個很重要的應用場景就是註冊時候的使用者名稱的查重。

其實這裡就使用了AJAX技術!當檔案框發生了輸入變化時,使用AJAX技術向伺服器傳送一個請求,然後伺服器會把查詢到的結果響應給瀏覽器,最後再把後端返回的結果展示出來。

  • 整個過程中頁面沒有重新整理,只是重新整理頁面中的區域性位置而已!

  • 當請求發出後,瀏覽器還可以進行其他操作,無需等待伺服器的響應!

當輸入使用者名稱後,把游標移動到其他表單項上時,瀏覽器會使用AJAX技術向伺服器發出請求,伺服器會查詢名為lemontree7777777的使用者是否存在,最終伺服器返回true表示名為lemontree7777777的使用者已經存在了,瀏覽器在得到結果後顯示“使用者名稱已被註冊!”。

  • 整個過程中頁面沒有重新整理,只是區域性重新整理了;

  • 在請求發出後,瀏覽器不用等待伺服器響應結果就可以進行其他操作;

AJAX的優缺點

優點:

  • AJAX使用JavaScript技術向伺服器傳送非同步請求;

  • AJAX請求無須重新整理整個頁面;

  • 因為伺服器響應內容不再是整個頁面,而是頁面中的部分內容,所以AJAX效能高;

  • 兩個關鍵點:1.區域性重新整理,2.非同步請求

jQuery實現的AJAX

最基本的jQuery傳送AJAX請求示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <style>
        .hide {
            display: none;
        }
    </style>
</head>
<body>
<p><input type="text" class="user"><span class="hide" style="color: red">使用者名稱已存在</span></p>

<script src="/static/jquery-3.3.1.min.js"></script>
{#下面這一項是基於jQuery的基礎上自動給我們的每一個ajax繫結一個請求頭資訊,類似於form表單提交post資料必須要有的csrf_token一樣#}
{#否則我的Django中介軟體裡面的校驗csrf_token那一項會認為你這個請求不是合法的,阻止你的請求#}
<script src="/static/setup_Ajax.js"></script>
<script>
    //給input框繫結一個失去焦點的事件
    $('.user').blur(function () {
        //$.ajax為固定用法,表示啟用ajax
        $.ajax({
            //url後面跟的是你這個ajax提交資料的路徑,向誰提交,不寫就是向當前路徑提交
            url:'',
            //type為標定你這個ajax請求的方法
            type:'POST',
            //data後面跟的就是你提交給後端的資料
            data:{'username':$(this).val()},
            //success為回撥函式,引數data即後端給你返回的資料
            success:function (data) {
                ret=JSON.parse(data);
                if (ret['flag']){
                    $('p>span').removeClass('hide');
                }
            }
        })
    });
</script>
</body>
</html>

views.py:

def index(request):
    if request.method=='POST':
        ret={'flag':False}
        username=request.POST.get('username')
        if username=='JBY':
            ret['flag']=True
            import json
            return HttpResponse(json.dumps(ret))
    return render(request,'index.html')

$.ajax引數

data引數中的鍵值對,如果值值不為字串,需要將其轉換成字串型別。

$("#b1").on("click", function () {
    $.ajax({
      url:"/ajax_add/",
      type:"GET",
      data:{"i1":$("#i1").val(),"i2":$("#i2").val(),"hehe": JSON.stringify([1, 2, 3])},
      success:function (data) {
        $("#i3").val(data);
      }
    })
  }) 

JS實現AJAX(瞭解)

var b2 = document.getElementById("b2");
  b2.onclick = function () {
    // 原生JS
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open("POST", "/ajax_test/", true);
    xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xmlHttp.send("username=q1mi&password=123456");
    xmlHttp.onreadystatechange = function () {
      if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
        alert(xmlHttp.responseText);
      }
    };
  };

AJAX請求如何設定csrf_token

不論是ajax還是誰,只要是向我Django提交post請求的資料,都必須校驗csrf_token來防偽跨站請求,那麼如何在我的ajax中弄這個csrf_token呢,我又不像form表單那樣可以在表單內部通過一句{% csrf_token %}就搞定了......

方式1

通過獲取隱藏的input標籤中的csrfmiddlewaretoken值,放置在data中傳送。

$.ajax({
  url: "/cookie_ajax/",
  type: "POST",
  data: {
    "username": "Tonny",
    "password": 123456,
    "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val()  // 使用JQuery取出csrfmiddlewaretoken的值,拼接到data中
  },
  success: function (data) {
    console.log(data);
  }
})

方式2

通過獲取返回的cookie中的字串 放置在請求頭中傳送。

注意:需要引入一個jquery.cookie.js外掛。

$.ajax({
  url: "/cookie_ajax/",
  type: "POST",
  headers: {"X-CSRFToken": $.cookie('csrftoken')},  // 從Cookie取csrf_token,並設定ajax請求頭
  data: {"username": "Q1mi", "password": 123456},
  success: function (data) {
    console.log(data);
  }
})

方式3

或者用自己寫一個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');

每一次都這麼寫太麻煩了,可以使用$.ajaxSetup()方法為ajax請求統一設定。

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);
    }
  }
});

將下面的檔案配置到你的Django專案的靜態檔案中,在html頁面上通過匯入該檔案即可自動幫我們解決ajax提交post資料時校驗csrf_token的問題,(匯入該配置檔案之前,需要先匯入jQuery,因為這個配置檔案內的內容是基於jQuery來實現的)

更多細節詳見:Djagno官方文件中關於CSRF的內容

練習(使用者名稱是否已被註冊)

功能介紹

在登錄檔單中,當用戶填寫了使用者名稱後,把游標移開後,會自動向伺服器傳送非同步請求。伺服器返回這個使用者名稱是否已經被註冊過。

 

案例分析

  • 頁面中給出登錄檔單;

  • 在username input標籤中繫結onblur事件處理函式。

  • 當input標籤失去焦點後獲取 username表單欄位的值,向服務端傳送AJAX請求;

  • django的檢視函式中處理該請求,獲取username值,判斷該使用者在資料庫中是否被註冊,如果被註冊了就返回“該使用者已被註冊”,否則響應“該使用者名稱可以註冊”。

答案就在前面的示例中,看你能不能找到了......

序列化

Django內建的serializers

什麼意思呢?就是我的前段想拿到由ORM得到的資料庫裡面的一個個使用者物件,我的後端想直接將例項化出來的資料物件直接傳送給客戶端,那麼這個時候,就可以用Django給我們提供的序列化方式

def ser(request):
    #拿到使用者表裡面的所有的使用者物件
    user_list=models.User.objects.all()
    #匯入內建序列化模組
    from django.core import serializers
    #呼叫該模組下的方法,第一個引數是你想以什麼樣的方式序列化你的資料
    ret=serializers.serialize('json',user_list)
    return HttpResponse(ret)

補充一個SweetAlert外掛示例

點選下載Bootstrap-sweetalert專案

 $("#b55").click(function () {
        swal({
                    title: "你確定要刪除嗎?",
                    text: "刪除可就找不回來了哦!",
                    type: "warning",
                    showCancelButton: true,  // 是否顯示取消按鈕
                    confirmButtonClass: "btn-danger",  // 確認按鈕的樣式類
                    confirmButtonText: "刪除",  // 確認按鈕文字
                    cancelButtonText: "取消",  // 取消按鈕文字
                    closeOnConfirm: false,  // 點選確認按鈕不關閉彈框
                    showLoaderOnConfirm: true  // 顯示正在刪除的動畫效果
                },
                function () {
                    var deleteId = 2;
                    $.ajax({
                        url: "/delete_book/",
                        type: "post",
                        data: {"id": deleteId},
                        success: function (data) {
                            if (data.code === 0) {
                                swal("刪除成功!", "你可以準備跑路了!", "success");
                            } else {
                                swal("刪除失敗", "你可以再嘗試一下!", "error")
                            }
                        }
                    })
                });
    })

上面這個二次確認的動態框樣式,你也可以直接應用到你的專案中

提醒事項:

1.上述的樣式類部分渲染的樣式來自於bootstrap中,所有建議在使用上述樣式時,將bootstrap的js和css也匯入了,這樣的情況下,頁面效果就不會有任何問題

2.彈出的上述模態框中,可能字型會被圖示掩蓋一部分,可通過調整字型的上外邊距來解決