09.Django基礎七之Ajax

来源:https://www.cnblogs.com/changxin7/archive/2019/09/28/11601850.html
-Advertisement-
Play Games

一 Ajax簡介 1.簡介 AJAX(Asynchronous Javascript And XML)翻譯成中文就是“非同步的Javascript和XML”。即使用Javascript語言與伺服器進行非同步交互,傳輸的數據為XML(當然,傳輸的數據不只是XML,現在更多使用json數據)。 AJAX 不 ...


一 Ajax簡介

1.簡介

    AJAX(Asynchronous Javascript And XML)翻譯成中文就是“非同步的Javascript和XML”。即使用Javascript語言與伺服器進行非同步交互,傳輸的數據為XML(當然,傳輸的數據不只是XML,現在更多使用json數據)。

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

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

    AJAX 不需要任何瀏覽器插件,但需要用戶允許JavaScript在瀏覽器上執行。

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

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

  AJAX除了非同步的特點外,還有一個就是:瀏覽器頁面局部刷新;(這一特點給用戶的感受是在不知不覺中完成請求和響應過程

2.示例

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

    html文件名稱為ajax_demo1.html,內容如下

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="x-ua-compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>AJAX局部刷新實例</title>
</head>
<body>

<input type="text" id="i1">+
<input type="text" id="i2">=
<input type="text" id="i3">
<input type="button" value="AJAX提交" id="b1">

<script src="/static/jquery-3.2.1.min.js"></script>
<script>
  $("#b1").on("click", function () {
    $.ajax({
      url:"/ajax_add/", //別忘了加雙引號
      type:"GET",  
      data:{"i1":$("#i1").val(),"i2":$("#i2").val()}, //object類型,鍵值形式的,可以不給鍵加引號
      success:function (data) {
        $("#i3").val(data);
      }
    })
  })
</script>
</body>
</html>

    views.py裡面的內容:

def ajax_demo1(request):
    return render(request, "ajax_demo1.html")


def ajax_add(request):    #time.sleep(10)  #不影響頁面發送其他的請求
    i1 = int(request.GET.get("i1"))
    i2 = int(request.GET.get("i2"))
    ret = i1 + i2
    return JsonResponse(ret, safe=False)    #return render(request,'index.html')  #返回一個頁面沒有意義,就是一堆的字元串,拿到了這個頁面,你怎麼處理,你要做什麼事情,根本就沒有意義

    urls.py裡面的內容

urlpatterns = [
    ...
    url(r'^ajax_add/', views.ajax_add),
    url(r'^ajax_demo1/', views.ajax_demo1),
    ...   
]

   啟動django項目,然後運行看看效果,頁面不刷新

3.AJAX常見應用情景

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

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

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

      a.整個過程中頁面沒有刷新,只是刷新頁面中的局部位置而已!

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

​     img

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

    a.整個過程中頁面沒有刷新,只是局部刷新了;

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

4.AJAX的優缺點

優點:

      1.AJAX使用JavaScript技術向伺服器發送非同步請求;

      2.AJAX請求無須刷新整個頁面;

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

5.作業

    寫一個登陸認證頁面,登陸失敗不刷新頁面,提示用戶登陸失敗,登陸成功自動跳轉到網站首頁。

    login.html,內容如下:

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div>
    用戶名:<input type="text" id="username">
    密碼:<input type="text" id="pwd">
    {% csrf_token %}
    <button id="sub">提交</button>
    <span style="color: red;font-size: 12px;" id="error"></span>
</div>

<script src="{% static 'jquery.js' %}"></script>

<script>
    $('#sub').click(function () {
        $.ajax({
            url:"{% url 'login' %}",
            type:'post',
            data:{username:$('#username').val(),pwd:$('#pwd').val(),csrfmiddlewaretoken:$('[name=csrfmiddlewaretoken]').val()},

            success:function (data) {
                data = JSON.parse(data);
                console.log(data,typeof data);
                if (data['status']){

                    location.href=data['home_url'];
                }
                else {
                    $('#error').text('用戶名或者密碼錯誤!')
                }
            }

        })


    })



</script>

</body>
</html>

    base.html,內容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>
    歡迎來到xxx官網
</h1>
</body>
</html>

    urls.py,內容如下

url(r'^login/', views.login,name='login'),
url(r'^home/', views.home,name='home'),

    views.py,內容如下

def login(request):
    res_dict = {'status':None,'home_url':None}
    if request.method == 'GET':
        return render(request,'login.html')
    else:
        uname = request.POST.get('username')
        pwd = request.POST.get('pwd')

        user_obj = models.UserInfo.objects.filter(name=uname,password=pwd).exists()
        import json
        if user_obj:

            res_dict['status'] = True
            res_dict['home_url'] = reverse('home')
            res_json_dict = json.dumps(res_dict)

            return HttpResponse(res_json_dict) #直接回覆字典格式是不可以的,必須轉換成json字元串,轉換成普通字元串也是不行的,因為前端需要對json進行反序列獲得這個字典,在通過字典的形式來操作數據。
        else:
            res_dict['status'] = False
            res_json_dict = json.dumps(res_dict)
            return HttpResponse(res_json_dict)
      # 如果你就是不使用JsonResponse的話,也可以給HttpResponse添加一個參數,content_type='application/json',那麼前端ajax拿到數據之後,也是不需要反序列化的,ajax的回調函數就收到的就是一個反序列化之後的一個對象,因為ajax接受到數據後,通過這個data_type或者content_type發現你發送來的是個json格式的數據,那麼ajax內容就自動將這個數據反序列化得到了js的數據對象,然後通過對象可以直接操作數據。      # return HttpResponse(res_json_dict,data_type='application/json')      # return JsonResponse(res_dict)
def home(request):

    return render(request,'base.html')

    還有一點註意一下,如果你想通過ajax來刪除表格中某條記錄,並且ajax裡面的url不寫死的情況下(url反向解析),那麼就需要下麵這種方式,實現url裡面參數的動態:

        img

    還有一個細節要註意:

      img

      並且刪除一條數據的時候,後端刪除成功之後,你通過後端給你的返回值判斷後端是否刪除成功,如果刪除成功,你有兩種方式來刪除前端頁面的對應一行的記錄,1:刷新頁面,2:如果不讓刷新頁面,那麼你就需要找到你點擊的這個按鈕的那一行的tr標簽,通過dom操作把它刪除

     ajax裡面寫$(this)時要註意的問題:還有一點註意,如果你添加某些dom對象的時候,如果你想在不刷新頁面的情況下來添加這個對象,那麼你要註意,如果這個對象也需要綁定事件的話,你需要用on來給和他相同的標簽對象來綁定事件。

      img

  在這裡補充個事情:

    settings配置文件裡面加上下麵這句話,意思是說,告訴django,如果別人請求我的路徑的時候,你不要自己處理別人輸入的路徑最後面的/了,如果這個值為True,而我們假如寫了一個url為url('^index/',views.test),如果用戶輸入的時127.0.0.1:8000/index的話,django會讓瀏覽器重新再發一次請求,並且在這個路徑後面加上/,也就成了127.0.0.1:8000/index/,此時和我們的url就能匹配上了,因為我們的url正則寫的就加了/,如果你將下麵這個值設置成false,那麼django就不會自動幫你做這個事情了,那麼用戶在輸入127.0.0.1:8000/index,沒有最後那個斜杠的路徑時,就無法和我們的url正則匹配上了,所以就找不到url了,就會報錯,但是註意,django只能幫你重定向讓瀏覽器再發一個get請求,如果你是post請求(非get請求),django就沒有辦法了,他還是幫你重新定向發送get請求,不能滿足你的需求,所以如果你用post方法提交數據的時候,就像上面這個ajax裡面的那個url寫的必須和你後端配置的那個url對應好,所以別忘瞭如果你後端url上url('^index/',views.test)這個index後面加了/,那麼你寫ajax往這個路徑下提交數據的時候,ajax裡面的url參數後面別忘了寫上/,讓這個url和後端url正則規則對應好。

      img

    

二 Ajax的使用

1.基於jQuery的實現

    看代碼:

<button class="send_Ajax">send_Ajax</button>
<script>

       $(".send_Ajax").click(function(){

           $.ajax({
               url:"/handle_Ajax/",
               type:"POST",
               data:{username:"chao",password:123},
               success:function(data){
                   console.log(data)
               },
               
               error: function (jqXHR, textStatus, err) {
                        console.log(arguments);
                    },

               complete: function (jqXHR, textStatus) {
                        console.log(textStatus);
                },

               statusCode: {
                    '403': function (jqXHR, textStatus, err) {
                          console.log(arguments);
                     },

                    '400': function (jqXHR, textStatus, err) {
                        console.log(arguments);
                    }
                }

           })

       })

</script>

2.基於原生js實現

    看代碼

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=chao&password=123456");
    xmlHttp.onreadystatechange = function () {
      if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
        alert(xmlHttp.responseText);
      }
    };
  };

3.Ajax-伺服器-Ajax流程圖

     img

4.ajax參數

    請求參數:

######################------------data---------################

       data: 當前ajax請求要攜帶的數據,是一個json的object對象,ajax方法就會預設地把它編碼成某種格式
             (urlencoded:?a=1&b=2)發送給服務端;此外,ajax預設以get方式發送請求。

             function testData() {
               $.ajax("/test",{     //此時的data是一個json形式的對象
                  data:{
                    a:1,
                    b:2
                  }
               });                   //?a=1&b=2
######################------------processData---------################

processData:聲明當前的data數據是否進行轉碼或預處理,預設為true,即預處理;if為false,
             那麼對data:{a:1,b:2}會調用json對象的toString()方法,即{a:1,b:2}.toString()
             ,最後得到一個[object,Object]形式的結果。
            
######################------------contentType---------################

contentType:預設值: "application/x-www-form-urlencoded"。發送信息至伺服器時內容編碼類型。
             用來指明當前請求的數據編碼格式;urlencoded:?a=1&b=2;如果想以其他方式提交數據,
             比如contentType:"application/json",即向伺服器發送一個json字元串:
               $.ajax("/ajax_get",{
             
                  data:JSON.stringify({
                       a:22,
                       b:33
                   }),
                   contentType:"application/json",
                   type:"POST",
             
               });                          //{a: 22, b: 33}

             註意:contentType:"application/json"一旦設定,data必須是json字元串,不能是json對象

             views.py:   json.loads(request.body.decode("utf8"))


######################------------traditional---------################

traditional:一般是我們的data數據有數組時會用到 :data:{a:22,b:33,c:["x","y"]},
              traditional為false會對數據進行深層次迭代;  

    響應參數:

dataType:  預期伺服器返回的數據類型,伺服器端返回的數據會根據這個值解析後,傳遞給回調函數。
            預設不需要顯性指定這個屬性,ajax會根據伺服器返回的content Type來進行轉換;
            比如我們的伺服器響應的content Type為json格式,這時ajax方法就會對響應的內容
            進行一個json格式的轉換,if轉換成功,我們在success的回調函數里就會得到一個json格式
            的對象;轉換失敗就會觸發error這個回調函數。如果我們明確地指定目標類型,就可以使用
            data Type。
            dataType的可用值:html|xml|json|text|script
            見下dataType實例

三 Ajax請求設置csrf_token

方式1

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

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

方式2

$.ajaxSetup({
    data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});

方式3(後面再說)

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

    註意:需要引入一個jquery.cookie.js插件。

<script src="{% static 'js/jquery.cookie.js' %}"></script>

$.ajax({
 
headers:{"X-CSRFToken":$.cookie('csrftoken')}, #其實在ajax裡面還有一個參數是headers,自定製請求頭,可以將csrf_token加在這裡,我們發contenttype類型數據的時候,csrf_token就可以這樣加
 
})

  詳述CSRF(Cross-site request forgery),中文名稱:跨站請求偽造,也被稱為:one click attack/session riding,縮寫為:CSRF/XSRF。攻擊者通過HTTP請求江數據傳送到伺服器,從而盜取回話的cookie。盜取回話cookie之後,攻擊者不僅可以獲取用戶的信息,還可以修改該cookie關聯的賬戶信息。

  img

  所以解決csrf攻擊的最直接的辦法就是生成一個隨機的csrftoken值,保存在用戶的頁面上,每次請求都帶著這個值過來完成校驗。

  那麼django中csrf認證怎麼玩的呢?

    官方文檔中說到,檢驗token時,只比較secret是否和cookie中的secret值一樣,而不是比較整個token。
    我又有疑問了,同一次登錄,form表單中的token每次都會變,而cookie中的token不便,django把那個salt存儲在哪裡才能保證驗證通過呢。直到看到源碼。

def _compare_salted_tokens(request_csrf_token, csrf_token):
    # Assume both arguments are sanitized -- that is, strings of
    # length CSRF_TOKEN_LENGTH, all CSRF_ALLOWED_CHARS.
    return constant_time_compare(
        _unsalt_cipher_token(request_csrf_token),
        _unsalt_cipher_token(csrf_token),
    )

def _unsalt_cipher_token(token):
    """
    Given a token (assumed to be a string of CSRF_ALLOWED_CHARS, of length
    CSRF_TOKEN_LENGTH, and that its first half is a salt), use it to decrypt
    the second half to produce the original secret.
    """
    salt = token[:CSRF_SECRET_LENGTH]
    token = token[CSRF_SECRET_LENGTH:]
    chars = CSRF_ALLOWED_CHARS
    pairs = zip((chars.index(x) for x in token), (chars.index(x) for x in salt))
    secret = ''.join(chars[x - y] for x, y in pairs)  # Note negative values are ok
    return secret

  

    token字元串的前32位是salt, 後面是加密後的token, 通過salt能解密出唯一的secret。
    django會驗證表單中的token和cookie中token是否能解出同樣的secret,secret一樣則本次請求合法。
    同樣也不難解釋,為什麼ajax請求時,需要從cookie中拿取token添加到請求頭中。

    Cookies Hashing:每一個表單請求中都加入隨機的Cookie,由於網站中存在XSS漏洞而被偷竊的危險。 
    HTTP refer:可以對伺服器獲得的請求來路進行欺騙以使得他們看起來合法,這種方法不能夠有效防止攻擊。 
    驗證碼:用戶提交的每一個表單中使用一個隨機驗證碼,讓用戶在文本框中填寫圖片上的隨機字元串,並且在提交表單後對其進行檢測。 
    令牌Token:一次性令牌在完成他們的工作後將被銷毀,比較安全。
    ...等等吧,還有很多其他的。

    

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

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

    註意:

      如果使用從cookie中取csrftoken的方式,需要確保cookie存在csrftoken值。

      如果你的視圖渲染的HTML文件中沒有包含 {% csrf_token %},Django可能不會設置CSRFtoken的cookie。

      這個時候需要使用ensure_csrf_cookie()裝飾器強制設置Cookie。

django.views.decorators.csrf import ensure_csrf_cookie


@ensure_csrf_cookie
def login(request):
    pass

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

四 Ajax文件上傳

請求頭ContentType

    ContentType指的是請求體的編碼類型,常見的類型共有3種:

1 application/x-www-form-urlencoded(看下圖)

      這應該是最常見的 POST 提交數據的方式了。瀏覽器的原生

表單,如果不設置 enctype 屬性,那麼最終就會以 預設格式application/x-www-form-urlencoded 方式提交數據,ajax預設也是這個。請求類似於下麵這樣(無關的請求頭在本文中都省略掉了):

POST http://www.example.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8

user=yuan&age=22   #這就是上面這種contenttype規定的數據格式,後端對應這個格式來解析獲取數據,不管是get方法還是post方法,都是這樣拼接數據,大家公認的一種數據格式,但是如果你contenttype指定的是urlencoded類型,但是post請求體裡面的數據是下麵那種json的格式,那麼就出錯了,服務端沒法解開數據。

      看network來查看我們發送的請求體:

        img

      點擊一下上面紅框的內容,你就會看到,這次post請求發送數據的原始格式

        img

2 multipart/form-data

      這又是一個常見的 POST 數據提交的方式。我們使用表單上傳文件時,必須讓 表單的 enctype 等於 multipart/form-data,form表單不支持發json類型的contenttype格式的數據,而ajax什麼格式都可以發,也是ajax應用廣泛的一個原因。直接來看一個請求示例:(瞭解)

POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA

------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="user"

chao
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png

PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

      這個例子稍微複雜點。首先生成了一個 boundary 用於分割不同的欄位,為了避免與正文內容重覆,boundary 很長很複雜。然後 Content-Type 里指明瞭數據是以 multipart/form-data 來編碼,本次請求的 boundary 是什麼內容。消息主體里按照欄位個數又分為多個結構類似的部分,每部分都是以 --boundary 開始,緊接著是內容描述信息,然後是回車,最後是欄位具體內容(文本或二進位)。如果傳輸的是文件,還要包含文件名和文件類型信息。消息主體最後以 --boundary-- 標示結束。關於 multipart/form-data 的詳細定義,請前往 rfc1867 查看。

      這種方式一般用來上傳文件,各大服務端語言對它也有著良好的支持。

      上面提到的這兩種 POST 數據的方式,都是瀏覽器原生支持的,而且現階段標準中原生 表單也只支持這兩種方式(通過 元素的 enctype 屬性指定,預設為 application/x-www-form-urlencoded。其實 enctype 還支持 text/plain,不過用得非常少)。

      隨著越來越多的 Web 站點,尤其是 WebApp,全部使用 Ajax 進行數據交互之後,我們完全可以定義新的數據提交方式,給開髮帶來更多便利。

3 application/json

      application/json 這個 Content-Type 作為響應頭大家肯定不陌生。實際上,現在越來越多的人把它作為請求頭,用來告訴服務端消息主體是序列化後的 JSON 字元串。由於 JSON 規範的流行,除了低版本 IE 之外的各大瀏覽器都原生支持 JSON.stringify,服務端語言也都有處理 JSON 的函數,使用 JSON 不會遇上什麼麻煩。

      JSON 格式支持比鍵值對複雜得多的結構化數據,這一點也很有用。記得以前做過一個項目時,需要提交的數據層次非常深,我就是把數據 JSON 序列化之後來提交的。不過當時我是把 JSON 字元串作為 val,仍然放在鍵值對里,以 x-www-form-urlencoded 方式提交。

       img

    如果在ajax裡面寫上這個contenttype類型,那麼data參數對應的數據,就不能是個object類型數據了,必須是json字元串,contenttype:'json',簡寫一個json,它也能識別是application/json類型

        img

        服務端接受到數據之後,通過contenttype類型的值來使用不同的方法解析數據,其實就是服務端框架已經寫好了針對這幾個類型的不同的解析數據的方法,通過contenttype值來找對應方法解析,如果有一天你寫了一個contenttype類型,定義了一個消息格式,各大語言及框架都支持,那麼別人也會寫一個針對你的contenttype值來解析數據的方法,django裡面不能幫我們解析contenttype值為json的數據格式,你知道他能幫你解析application/x-www-form-urlencoded 和multipart/form-data(文件上傳會用到)就行了,如果我們傳json類型的話,需要我們自己來寫一個解析數據的方法,其實不管是什麼類型,我們都可以通過原始發送來的數據來進行加工處理,解析出自己想要的數據,這個事情我們在前面自己寫web框架的時候在獲取路徑那裡就玩過了,還記得嗎?

          img

  $.ajax({
            url:"{% url 'home' %}",
            type:'post',
            headers:{
                "X-CSRFToken":$.cookie('csrftoken'), #現在先記住,等學了cookies你就明白了
                contentType:'json',
            },

            data:JSON.stringify({ //如果我們發送的是json數據格式的數據,那麼csrf_token就不能直接寫在data裡面了,沒有效果,必須通過csrf的方式3的形式來寫,寫在hearders(請求頭,可以寫一些自定製的請求頭)裡面,註意,其實contentType也是headers裡面的一部分,寫在裡面外面都可以
                name:name,
                //csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(),
            }),
            success:function (response) {

            }

        })

基於form表單的文件上傳

模板部分

<form action="" method="post" enctype="multipart/form-data"> #上面說的其他兩種contenttype都是鍵值的形式發送數據,這種form_data的格式一般是把大數據一段一段隔開的
      用戶名 <input type="text" name="user">
      頭像 <input type="file" name="avatar">  #如果不用form_data格式來發,那麼預設的是urlencoded的格式,這個標簽的數據會組成avatar:文件名字來進行發送
    <input type="submit">
</form>

視圖部分

def index(request):
    print(request.body)   # 原始的請求體數據
    print(request.GET)    # GET請求數據
    print(request.POST)   # POST請求數據
    print(request.FILES)  # 上傳的文件數據


    return render(request,"index.html")

  upload.py,內容如下:

def upload(request):

    if request.method == 'GET':

        return render(request,'upload.html')
    else:
        print(request.POST)
        username = request.POST.get('user')
        file_obj = request.FILES.get('file_obj') #獲得文件數據對象
        print('>>>',file_obj,type(file_obj))
        #>>> jaden博客.txt <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>,一個文件對象,可以理解為一個文件句柄
        file_name = file_obj.name #jaden博客.txt
        print(file_name)
        # 將數據寫到文件裡面,需要名字,需要數據
        with open(file_name,'wb') as f: #直接把文件名字放這裡,那麼文件將直接生成在django的整個項目目錄下,因為django配置的系統搜索的根路徑就是咱們的項目文件夾路徑,那個BASE_DIR,一般我們需要自己建立一個文件夾專門存放上傳的文件      #所以需要我們自己來拼接一個路徑放到這裡,os.path.join(settings.BASE_DIR,'media','img',file_name)
            # f.write()  #不能一下寫進去,占用的內容太多,要一點一點寫
            for data in file_obj: #讀數據
                f.write(data)  #每次讀取的data不是固定長度的,和讀取其他文件一樣,每次讀一行,識別符為\r  \n  \r\n,遇到這幾個符號就算是讀了一行
       #for chunks in file_obj.chunks(): #chunks()預設一次返回大小為經測試為65536B,也就是64KB,最大為2.5M,是一個生成器         #  f.write(chunks)

    通過js來找文件對象

      img

基於Ajax的文件上傳

模板

<form> #用不用form沒關係,這裡就是個盒子的作用,一般寫form標簽是為了提示別人,這個地方的內容是要提交的
      {% csrf_token %}      用戶名 <input type="text" id="user">
      頭像 <input type="file" id="avatar">
     <input type="button" id="ajax-submit" value="ajax-submit">
</form>

<script>

    $("#ajax-submit").click(function(){
        var formdata=new FormData(); #ajax上傳文件的時候,需要這個類型,它會將添加給它的鍵值對加工成formdata的類型
        formdata.append("user",$("#user").val());  #添加鍵值的方法是append,註意寫法,鍵和值之間是逗號
     formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val()); #別忘了csrf_token
        formdata.append("avatar_img",$("#avatar")[0].files[0]);
        $.ajax({

            url:"",
            type:"post",
            data:formdata, #將添加好數據的formdata放到data這裡
            processData: false ,    // 不處理數據
            contentType: false,    // 不設置內容類型

            success:function(data){
                console.log(data)
            }
        })

    })

</script>

      或者使用

var form = document.getElementById("form1");
var fd = new FormData(form);

      這樣也可以直接通過ajax 的 send() 方法將 fd 發送到後臺。

      註意:由於 FormData 是 XMLHttpRequest Level 2 新增的介面,現在 低於IE10 的IE瀏覽器不支持 FormData。

視圖

def index(request):

    if request.is_ajax():

        print(request.body)   # 原始的請求體數據
        print(request.GET)    # GET請求數據
        print(request.POST)   # POST請求數據
        print(request.FILES)  # 上傳的文件數據

        return HttpResponse("ok")


    return render(request,"index.html")

  檢查瀏覽器的請求頭:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryaWl9k5ZMiTAzx3FT

    關於django後端代碼接受上傳文件的方法

當Django處理上傳一個文件的時候,文件數據被放在request.FILES中。這個文檔解釋文件怎麼樣被存儲在磁碟上或者記憶體中,怎樣定製預設的行為。
基本文件上傳
考慮一個包含FileField的簡單的表單:
from  django  import  forms
classUploadFileForm(forms.Form):
   title=forms.CharField(max_length=50)
   file=forms.FileField()
一個處理這個表單的視圖將在request.FILES中接受文件數據 ,request.FILES是一個字典,它對每個FileField(或者是ImageField,或者是其他的FileField的子類)都包含一個key.所以 從上面的表單中來的數據將可以通過request.FILES['file']鍵來訪問.
註意request.FILES只有 在request方法是POST並且發出POST請求的

有屬性enctype="multipart/form-data".否則,request。FILES將是空的。
看另一個簡單的;
from fdjango.http improt HttpResponseRedirect
from django.shortcuts import render_to_response
from somewhere import handle_uploaded_file
def upload_file(request):
    if request.method == 'post':
        form =  UploadFileForm(rquest.POST,request.FILES)
        if form.is_valid():
            handle_uploaded_file(request.FILES['file'])
            return HttpResponseRedirect('/success/ur/')
   else:
        form = UploadFileForm()
    return render_to_response('upload.html',{'form':form})
要註意,我們必須將request.FILES傳遞到表單的構造器中;這就是文件數據怎樣和表單沾上邊的 。
處理上傳的文件
最後的難題是怎樣處理從request.FILES中獲得的真實的文件。這個字典的每個輸入都是一個UploadedFile對象——一個上傳之後的文件的簡單的包裝。
你通常會使用下麵的幾個方法來訪問被上傳的內容:
UploadedFile.read():從文件中讀取整個上傳的數據。小心整個方法:如果這個文件很大,你把它讀到記憶體中會弄慢你的系統。你可以想要使用chunks()來代替,看下麵;
UploadedFile.multiple_chunks():如果上傳的文件足夠大需要分塊就返回真。預設的這個值是2.5兆,當然這個值是可以調節的,看下麵的UploadedFile.chunks():一個產生器,返迴文件的塊。如果multiple_chunks()是真的話,你應該在一個迴圈中使用這個方法,而不是使用read();
UploadedFile.name:上傳文件的名字(比如m_file.txt)
UploadedFile.size:以bytes表示的上傳的文件的大小。
還有其他的幾個方法和屬性。你可以自己去查。
把他們放在一起,這裡是一個你處理上傳文件的通常方法:
def handle_uploaded_file(f):
    destination = open('some/file/name.txt','wb+')
    for chunk in f.chunks(): 
        destination.write(chunk)
    destination.close()
在UploadedFile.chunks()上迴圈而不是用read()保證大文件不會大量使用你的系統記憶體。
上傳的數據存在哪裡?
在你保存上傳的文件之前,數據需要被保存在某些地方。預設呢的,如果一個上傳的文件小於2.5兆,Django會將上傳的東西放在記憶體里。這意味著只要從記憶體讀取數據並保存到硬碟上,所以很快。然而,如果一個上傳的文件太大,Django將將上傳的文件寫到一個臨時的文件中,這個文件在你的臨時文件路徑中。在Unix-like的平臺上意味著你可以預見Django產生一個文件保存為/tmp/tmpzfp6I6.upload的文件。如果這個文件足夠大,你可以觀察到這個文件的大小在增大。
很多細節--2.5M;/tmp;等 等 都是簡單的看上去合理的預設值。繼續閱讀看看你怎麼樣個性化或者完全替代掉上傳行為。
改變上傳處理行為
三個設置改變Django的上傳處理行為:
FILE_UPLOAD_MAX_MEMORY_SIZE:以bytes為單位的到記憶體中的最大大小,。比這個值大的文件將被先存到磁碟上。預設是2.5兆
FILE_UPLOAD_TEMP_DIR:比FILE_UPLOAD_MAX_MEMORY_SIZE大的文件將被臨時保存的地方。預設是系統標準的臨時路徑。
FILE_UPLOAD_PERMISSIONS:如果這個沒有給出或者是None,你將獲得獨立於系統的行為。大多數平臺,臨時文件有一個0600模式,從記憶體保存的文件將使用系統標準umask。
FILE_UPLOAD_HANDLERS:上傳文件的處理器。改變這個設置允許完全個性化——甚至代替——Django的上傳過程。
預設是:
("django.core.files.uploadhandler.MemoryFileUploadHandler",
 "django.core.files.uploadhandler.TemporaryFileUploadHandler",)
UploadedFile 對象
class UploadedFile
作為那些重File繼承的補充,素有的UploadedFile對象定義了下麵的方法和屬性:
UploadedFile.content_type
文件的content_type頭(比如text/plain
 orapplication/pdf
)。像用戶提供的任何數據一樣,你不應該信任上傳的數據就是這個類型。你仍然要驗證這個文件包含這個頭聲明的content-type——“信任但是驗證”。
UploadedFile.charset
對於text/*的content-types,瀏覽器提供的字元集。再次,“信任但是驗證”是最好的策略。
UploadedFile.temporary_file_path():只有被傳到磁碟上的文件才有這個方法,它返回臨時上傳文件的全路徑。
註意:
 像通常的Python文件,你可以迭代上傳的文件來一行一行得讀取文件:
for line in uploadedfile:
    do_something_with(line)
然而,不同於標準Python文件,UploadedFile值懂得/n(也被稱為Unix風格)的結尾。如果你知道你需要處理有不同風格結尾的文件的時候,你要在你的視圖中作出處理。
上傳處理句柄:
當一個用戶上傳一個文件,Django敬愛那個這個文件數據傳遞給上傳處理句柄——一個處理隨著文件上傳處理文件的小類。上傳處理句柄被FILE_UPLOAD_HANDLERS初始化定義,預設是:
(
"django.core.files.uploadhandler.MemoryFileUploadHandler"
,
 "django.core.files.uploadhandler.TemporaryFileUploadHandler"
,)
這兩個提供了Django處理小文件和大文件的預設上產行為。
你可以個性化處理句柄來個性化Django處理文件的行為。比如你可以使用個性化的處理句柄來強制用戶配額,實時地壓縮數據,渲染進度條,甚至在保存在本地的同時向另一個存儲地發送數據。
實時修改上傳處理句柄
有的時候某些視圖要使用不同的上傳行為。這種情況下,你可以重寫一個上傳處理句柄,通過request.upload_handlers來修改。預設的,這個列表包含FILE_UPLOAD_HANDLERS提供的處理句柄,但是你可以像修改其他列表一樣修改這個列表。
比如,加入你寫了一個叫做
ProgressBarUploadHandler
 的處理句柄。你可以通過下麵的形式加到你的上傳處理句柄中:
request.upload_handlers.insert(0,ProgressBarUploadHandler())
你贏使用list.insert()在這種情況下。因為進度條處理句柄需要首先執行。記住,處理句柄按照順序執行。
如果你像完全代替掉上傳處理句柄,你可以賦值一個新的列表:
request.upload_handlers=[ProgressBarUploadHandler()]
註意:你只能在訪問request.POST或者request.FILES之前修改上傳處理句柄。——如果上傳處理開始後再改就沒用了。如果你在修改reqeust.uplaod_handlers之前訪問了request.POST
 or request.FILES
 ,Django將拋出一個錯誤。
所以,在你的視圖中儘早的修改上傳處理句柄。

寫自定義的上傳處理句柄:

所有的上傳處理句柄都應 是 django.core.files.uploadhandler.FileUploadHandler的子類。你可以在任何你需要的地方定義句柄。
需要的方法:

自定義的上傳處理句柄必須定義一下的方法:

FileUploadHandler.receive_data_chunk(self,raw_data,start):從文件上傳中接收塊。

raw_data是已經上傳的位元組流

start是raw_data塊開始的位置

你返回的數據將被傳遞到下一個處理句柄的receive_data_chunk方法中。這樣一個處理句柄就是另一個的過濾器了。

返回None將阻止後面的處理句柄獲得這個塊,當你 自己存儲這個數據,而不想其他處理句柄存儲拷貝時很有用。

如果你觸發一個StopUpload或者SkipFile異常,上傳將被放棄或者文件被完全跳過。

FileUploadHandler.file_complete(self, file_size)


當 文件上傳完畢時調用。

處理句柄應該返回一個UploadFile對象,可以存儲在request.FILES中。處理句柄也可以返回None來使得UploadFile對象應該來自後來的上傳處理句柄。


剩下的就是可選的一些方法實現。


FILE_UPLOAD_MAX_MEMORY_SIZE = 209715200 
FILE_UPLOAD_MAX_MEMORY_SIZE = 209715200


在你本機先好好測試一下,它是如何占用記憶體,什麼時候開始存入temp目錄,怎麼遷移到upload目錄底下的

文件上傳的時候,如果一個上傳的文件小於2.5兆,Django會將上傳的東西放在記憶體里,如果上傳的文件大於2.5M,Django將整個上傳的文件寫到一個臨時的文件中,這個文件在臨時文件路徑中。上傳完畢後,將調用View中的_Upload()方法將臨時文件夾中的臨時文件分塊寫到上傳文件的存放路徑下,每塊的大小為64K,寫完後臨時文件將被刪除。


UploadedFile.multiple_chunks():如果上傳的文件足夠大需要分塊就返回真。預設的這個值是2.5兆,當然這個值是可以調節的,看下麵的UploadedFile.chunks():一個產生器,返迴文件的塊。如果multiple_chunks()是真的話,你應該在一個迴圈中使用這個方法,而不是使用read();

在你保存上傳的文件之前,數據需要被保存在某些地方。預設呢的,如果一個上傳的文件小於2.5兆,Django會將上傳的東西放在記憶體里。這意味著只要從記憶體讀取數據並保存到硬碟上,所以很快。然而,如果一個上傳的文件太大,Django將上傳的文件寫到一個臨時的文件中,這個文件在你的臨時文件路徑中。在Unix-like的平臺上意味著你可以預見Django產生一個文件保存為/tmp/tmpzfp6I6.upload的文件。如果這個文件足夠大,你可以觀察到這個文件的大小在增大。

三個設置改變Django的上傳處理行為:
FILE_UPLOAD_MAX_MEMORY_SIZE:以bytes為單位的到記憶體中的最大大小,。比這個值大的文件將被先存到磁碟上。預設是2.5兆
FILE_UPLOAD_TEMP_DIR:比FILE_UPLOAD_MAX_MEMORY_SIZE大的文件將被臨時保存的地方。預設是系統標準的臨時路徑。
FILE_UPLOAD_PERMISSIONS:如果這個沒有給出或者是None,你將獲得獨立於系統的行為。大多數平臺,臨時文件有一個0600模式,從記憶體保存的文件將使用系統標準umask。

練習(用戶名是否已被註冊)

功能介紹

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

案例分析

  • 頁面中給出註冊表單;
  • 在username input標簽中綁定onblur事件處理函數。
  • 當input標簽失去焦點後獲取 username表單欄位的值,向服務端發送AJAX請求;
  • django的視圖函數中處理該請求,獲取username值,判斷該用戶在資料庫中是否被註冊,如果被註冊了就返回“該用戶已被註冊”,否則響應“該用戶名可以註冊”。
def index(request):

    if request.method == 'POST':
        print(request.POST)
        print('files',request.FILES)
        # book_objs = models.Book.objects.all()
        # ret = serializers.serialize('json', book_objs,cls=JsonCustomEncoder) #同樣無法序列化時間
        # ret = serializers.serialize('json', book_objs,cls=JsonCustomEncoder) #同樣無法序列化時間,無法和json一樣引入cls=JsonCustomEncoder這個類來解決日期時間格式數據的序列化
        #得到的結果[{"model": "app01.book", "pk": 1, "fields": {"name": "python", "date": null, "img": ""}}, {"model": "app01.book", "pk": 2, "fields": {"name": "linux", "date": null, "img": ""}}]
        #得到的結果的格式也是比較繁瑣,所以不推薦使用django自帶的serializers序列化器來序列化我們的queryset類型的數據
        #推薦寫法:
        ret = models.Book.objects.all().values()
        print(ret)
        # print(request.body)
        import json
        ret = json.dumps(list(ret),cls=JsonCustomEncoder)
        print(ret)
        print(type(ret))
        # return HttpResponse(ret,content_type='application\json')
        return JsonResponse(ret,safe=False)

五 關於json

1.什麼是json

  • JSON 指的是 JavaScript 對象表示法(JavaScript Object Notation)
  • JSON 是輕量級的文本數據交換格式
  • JSON 獨立於語言 *
  • JSON 具有自我描述性,更易理解

  • JSON 使用 JavaScript 語法來描述數據對象,但是 JSON 仍然獨立於語言和平臺。JSON 解析器和 JSON 庫支持許多不同的編程語言。

    啥都別多說了,上圖吧!

img

      json數據類型和python數據類型的對比:

      img

       object和python的dict類型是差不多的,但是要求裡面必須是雙引號,string和list、tuple等也是一樣的,都是雙引號。python中的datetime等時間日期類型是不能進行json序列化的,因為json沒有對應的格式,上面的這幾種數據類型雖然進行json.dumps序列化之後都是個字元串,但是也是有格式的

        img

        

    前端ajax拿到後端返回的一個python的json模塊序列化之後的一個json字元串,那麼js通過自己的json介面,將接受到的json字元串來反序列化為js自己語言能夠識別的數據類型,然後再進行操作。      

    相當於我有一個json方法,你有一個json方法,你給我發數據必須是json字元串的格式,那麼你就需要將你的數據類型序列化為json的字元串,那麼序列化的時候,就把你的數據序列化為了符合json標準的字元串,然後我接收到這個字元串之後,我通過我的json方法,將數據轉換為我的語言支持的數據類型。在進行反序列化的時候,如果你的字元串不符合json的格式,那麼反序列化的時候就會報錯,所以只要你是通過json序列化成的字元串,都是能夠json反序列化的,因為json序列化的時候,就把你的數據改為了符合json標準的字元串形式,例如:裡面的單引號,序列化後變成了雙引號。

    合格的json對象:

["one", "two", "three"]
{ "one": 1, "two": 2, "three": 3 } #這就是一個json的object類型,符合json的標準格式,就可以通過dumps來進行序列化
{"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;}  // 不能使用函數和日期對象
}

    看一下普通字元串和json字元串,在進行序列化的時候的區別

import json
# s = "{'name':'chao','age':18}" #普通字元串,每加引號的沒問題,加了引號的,必須是雙引號才能使用json.loads()。
s = '{"name":"chao","age":18}'   #json字元串,裡面必須是雙引號
ret = json.loads(s)
print(ret)
print(ret['name'])

2.js的stringify與parse方法

    JavaScript中關於JSON對象和字元串轉換的兩個方法:

    JSON.parse(): 用於將一個 JSON 字元串轉換為 JavaScript 對象 

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

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

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

3.和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 少得多,可以大大得節約傳輸數據所占用得帶寬。

4.ajax和服務端的數據交互時的序列化問題

  當我們給ajax回覆的不是一個字元串,而是其他數據類型的時候,需要我們將數據轉換為json字元串進行發送,這樣好配合js進行json字元串的處理,不然發送或者接受的是普通字元串的話,沒辦法處理成原來的數據類型。

  這就用到了我們前面的視圖函數中那個JsonResponse了,看博客,裡面response的部分

  還要註意ajax中的data參數:

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

5.Django內置的serializers做序列化

    看代碼:

def books_json(request):
    book_list = models.Book.objects.all()[0:10]
    from django.core import serializers
    ret = serializers.serialize("json", book_list)
    return HttpResponse(ret)

  通過json學列化時間日期格式數據的時候需要註意,不能直接序列化,我寫了一個類,可以借用:

  

import json
from datetime import datetime
from datetime import date

#對含有日期格式數據的json數據進行轉換
class JsonCustomEncoder(json.JSONEncoder):
    def default(self, field):
        if isinstance(field,datetime):
            return field.strftime('%Y-%m-%d %H:%M:%S')
        elif isinstance(field,date):
            return field.strftime('%Y-%m-%d')
        else:
            return json.JSONEncoder.default(self,field)


d1 = datetime.now()

dd = json.dumps(d1,cls=JsonCustomEncoder)
print(dd)

六 補充一個SweetAlert插件示例

看效果:

    img

  點擊下載Bootstrap-sweetalert項目

$(".btn-danger").on("click", function () {
  swal({
    title: "你確定要刪除嗎?",
    text: "刪除可就找不回來了哦!",
    type: "warning",
    showCancelButton: true,
    confirmButtonClass: "btn-danger",
    confirmButtonText: "刪除",
    cancelButtonText: "取消",
    closeOnConfirm: false
    },
    function () {
      var deleteId = $(this).parent().parent().attr("data_id");
      $.ajax({
        url: "/delete_book/",
        type: "post",
        data: {"id": deleteId},
        success: function (data) {
          if (data.status === 1) {
            swal("刪除成功!", "你可以準備跑路了!", "success");
          } else {
            swal("刪除失敗", "你可以再嘗試一下!", "error")
          }
        }
      })
    });
})

  項目中簡單應用:

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.0-dist/dist/css/bootstrap.min.css' %}">
    <link rel="stylesheet" href="{% static 'bootstrap-sweetalert-master/dist/sweetalert.css' %}">
</head>
<body>

<div>
    <button class="btn btn-danger">刪除</button>
</div>

</body>
<script src="{% static 'bootstrap-3.3.0-dist/dist/jQuery/jquery-3.1.1.js' %}"></script>
<script src="{% static 'bootstrap-3.3.0-dist/dist/js/bootstrap.min.js' %}"></script>
<script src="{% static 'bootstrap-sweetalert-master/dist/sweetalert.js' %}"></script>
<script>

    $(".btn-danger").on("click", function () {
        swal({
                title: "你確定要刪除嗎?",
                text: "刪除可就找不回來了哦!",
                type: "warning",
                showCancelButton: true,
                confirmButtonClass: "btn-danger",
                confirmButtonText: "我已經下定決心",
                cancelButtonText: "容我三思",
                closeOnConfirm: false
            },
            function () {
                var deleteId = $(this).parent().parent().attr("data_id");
                $.ajax({
                    url: "/delete_book/",
                    type: "post",
                    data: {"id": deleteId},
                    success: function (data) {
                        console.log(data,typeof data);
                        if (data === '1') {
                            swal("刪除成功!", "你可以準備跑路了!", "success");
                        } else {
                            swal("刪除失敗", "你可以再嘗試一下!", "error")
                        }
                    }
                })
            });
    })
</script>
</html>

複製代碼

urls.py

url(r'^delete_book/', views.delete_book,name='delete_book'),

views.py

def delete_book(request):

    import random
    ret = str(random.randint(1,2))
    return HttpResponse(ret)

七 同源策略與Jsonp

同源策略

    同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響。可以說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。

    同源策略,它是由Netscape提出的一個著名的安全策略。現在所有支持JavaScript 的瀏覽器都會使用這個策略。所謂同源是指,功能變數名稱,協議,埠相同。當一個瀏覽器的兩個tab頁中分別打開來 百度和谷歌的頁面當瀏覽器的百度tab頁執行一個腳本的時候會檢查這個腳本是屬於哪個頁面的,即檢查是否同源,只有和百度同源的腳本才會被執行。如果非同源,那麼在請求數據時,瀏覽器會在控制臺中報一個異常,提示拒絕訪問。

示例項目1:  

        

==================================http://127.0.0.1:8001項目的index
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</ti

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一.基本知識 HTML 指的是超文本標記語言: HyperText Markup Language HTML 標記標簽通常被稱為 HTML 標簽 (HTML tag) <標簽>內容</標簽> HTML 元素包含了開始標簽與結束標簽,元素的內容是開始標簽與結束標簽之間的內容,元素屬性是 HTML 元素 ...
  • <!DOCTYPE html> <html> <head> <title>vue-resource</title> <meta charset="utf-8"> </head> <body> <div id="app"> <input type="button" value="get請求" @cli... ...
  • 在vue中實現頁面刷新有不同的方法: 如:this.$router.go(0),location.reload()等,但是或多或少會存在問題,如頁面會一閃等 所以建議使用[provide/inject]實現刷新 該方法t簡單的來說就是在父組件中 1.設置provider 2.然後在子組件中通過inj ...
  • 1、Object構造函數 此方法的缺點十分明顯那就是要寫大量的代碼。 2、對象字面量創建 字面量的缺點是當我i們創建多個相似的對象的時候,它仍然不夠靈活,依然會產生重覆代碼。 3、工廠模式 console.log(person('tom', 18)) console.log(person('jony ...
  • 摘要: 理解JS執行原理。 原文: "JavaScript 是如何運行的?" 作者: "hengg" "Fundebug" 經授權轉載,版權歸原作者所有。 什麼是JavaScript? 我們來確認一下JavaScript的定義:JavaScript 是一門解釋型的動態語言。 解釋型語言是相對於編譯型 ...
  • Vue 綜合了 Angualr 和 React 的優點,因其易上手,輕量級,受到了廣泛應用。成為了是時下火熱的前端框架,吸引著越來越多的前端開發者! 本文將通過一個最簡單的拖拽例子帶領大家快速上手 Vue 組件 Vue Draggable。 首先,需要在工作環境中配置好 Vue cli,創建一個 v ...
  • 最近利用Vue和element ui仿寫了個小頁面,記一哈分頁和搜索功能的簡單實現。 首頁 emmmm..... 搜索框輸入..... 搜索完成 數據是直接寫在這裡面的: element ui 中的分頁 主頁照片: 實現分頁的關鍵: 別忘了在data() 下添加 search: ' ', filer ...
  • 享元模式(Flyweight): 定義: 運用共用技術有效地支持大量細粒度對象的復用。享元模式可以避免大量相似類的開銷,在軟體開發中如果需要生成大量細粒度的類實例,而這些類實例除了幾個參數外基本上相同,那麼這時就可以使用享元模式大幅度減少實例化類的數量。如果能把這些參數移動到實例外,在方法調用時將他 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...