Django:之傳遞數據給JS、Ajax和Ajax CSRF認證

Django傳遞數據給JSjavascript

有時候咱們想把一個list或者dict傳遞給javascript,處理後顯示到網頁上,好比要用js進行可視化到數據。html

請注意:若是是不處理,直接顯示在網頁上,用Django模版就能夠了,請看前面的教程。java

這裏講述兩種方法:python

1、頁面加載完成後,在頁面上操做,在頁面上經過ajax方法獲得新的數據(再向服務器發送一次請求)並顯示在網頁上,在這種狀況適用於頁面不刷新的狀況下,動態加載一些內容。好比用戶輸入一個值或者點擊某個地方,動態地把相應內容顯示在網頁上。jquery

這種請詳見下面Django Ajax一節的內容。ajax

2、直接在視圖函數(views.py中的函數)中渲染一個list或dict的內容,和網頁其它部分一塊兒顯示到網頁上(一次性地渲染,仍是同一次請求)。django

views.py編程

from __future__ import unicode_literals
from django.shortcuts import render
 
def home(request):
    List = ['吳老二博客', '渲染Json到模板']
    return render(request, 'home.html', {'List': List})

home.html中的一部分json

<script type="text/javascript">
    var List = {{ List }};
    alert(List);
</script>

須要注意的是,咱們若是直接這麼作,傳遞到js的時候,網頁的內容會被轉義獲得的格式會報錯。訪問時會獲得Uncaught SyntaxError: Unexpected token ILLEGAL數組

須要注意兩點:

一、views.py中返回的函數中的值要用json.dumps()處理

二、在網頁上要加一個safe過濾器。

views.py

# -*- coding: utf-8 -*-
 
from __future__ import unicode_literals
 
import json
from django.shortcuts import render
 
def home(request):
    List = ['吳老二博客', '渲染Json到模板']
    Dict = {'site': '吳老二博客', 'author': '吳老二'}
    return render(request, 'home.html', {
            'List': json.dumps(List),
            'Dict': json.dumps(Dict)
        })

home.html只給出了js核心部分:

//列表
var List = {{ List|safe }};
//字典
var Dict = {{ Dict|safe }};

若是你對js比較熟悉,至此爲止,下面的不用於看了,若是不太熟悉,能夠參考下面的更詳細的代碼。

html徹底代碼及完整代碼下載(最後面):

<!DOCTYPE html>
<html>
<head>
<title>歡迎光臨 吳老二博客!</title>
<script src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<div id="list"> 學習 </div>
<div id='dict'></div>
<script type="text/javascript">
    //列表
    var List = {{ List|safe }};
 
    //下面的代碼把List的每一部分放到頭部和尾部
    $('#list').prepend(List[0]);
    $('#list').append(List[1]);
 
    console.log('--- 遍歷 List 方法 1 ---')
    for(i in List){
        console.log(i);// i爲索引
    }
 
    console.log('--- 遍歷 List 方法 2 ---')
    for (var i = List.length - 1; i >= 0; i--) {
        // 鼠標右鍵,審覈元素,選擇 console 能夠看到輸入的值。
        console.log(List[i]);
    };
 
    console.log('--- 同時遍歷索引和內容,使用 jQuery.each() 方法 ---')
    $.each(List, function(index, item){
        console.log(index);
        console.log(item);
    });
 
 
    // 字典
    var Dict = {{ Dict|safe }};
    console.log("--- 兩種字典的取值方式  ---")
    console.log(Dict['site']);
    console.log(Dict.author);
     
    console.log("---  遍歷字典  ---");
    for(i in Dict) {
        console.log(i + Dict[i]);//注意,此處 i 爲鍵值
    }
</script>
</body>
</html>

完整代碼下載:json.zip(基於Django 1.8,注意settings.py文件和低版本可能不兼容,其它部分相同)  

Django Ajax

有時候咱們須要在不刷新的狀況下載入一些內容,在網頁的基本知識中咱們介紹了ajax技術。

在本文中講解如何用Django來實現不刷新網頁的狀況下加載一些內容。

因爲用jQuery實現ajax比較簡單,因此咱們用jQuery庫來實現,想用原生的javascript的同窗能夠參考:ajax教程,下面也有例子提供下載。

本節有多個實例提供下載,經過看代碼能夠更快的學習。

第一節,源代碼下載:ajax.zip

這裏用Django表單第一節中的一個例子,咱們要實現的是在不刷新的狀況下顯示計算結果到頁面上。修改index.html文件

<!DOCTYPE html>
<html>
<body>
<p>請輸入兩個數字</p>
<form action="/add/" method="get">
    a: <input type="text" id="a" name="a"> <br>
    b: <input type="text" id="b" name="b"> <br>
    <p>result: <span id='result'></span></p>
    <button type="button" id='sum'>提交</button>
</form>
 
<script src="http://apps.bdimg.com/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
    $(document).ready(function(){
      $("#sum").click(function(){
        var a = $("#a").val();
        var b = $("#b").val();
 
        $.get("/add/",{'a':a,'b':b}, function(ret){
            $('#result').html(ret)
        })
      });
    });
</script>
</body>
</html>

在原來的基礎上,在一些元素上加了id,以便於獲取值和綁定數據,而後咱們用了jQuery.get()方法,並用$(selector).html()方法將結果顯示在頁面上,以下圖:

備註:關於請求頭和request.is_ajax()方法使用

views.py中能夠用request.is_ajax()方法判斷是不是ajax請求,須要添加一個HTTP請求頭:原生javascript:

xmlhttp.setRequestHeader("X-Requested-With", "XMLHttpRequest");

用jQuery:

用 $.ajax 方法代替 $.get,由於 $.get 在 IE 中不會發送 ajax header

服務器端會將請求頭的值所有大寫,中劃線改爲下劃線,並在非標準的頭前面加上HTTP_,這個過程能夠認爲至關於如下Python代碼:

STANDARD_HEADERS = ['REFER', 'HOST', ...] # just for example
 
def handle_header(value):
    value = value.replace('-', '_').upper()
 
    if value in STANDARD_HEADERS:
        return value
 
    return 'HTTP_' + value

判斷ajax方法,以及原生的javascript實現ajax的示例下載:views_ajax.zip

第二節,源代碼下載:ajax_ist_dict.zip

更富在的例子,傳遞一個數組或字典到網頁,由JS處理,再顯示出來。

views.py

from django.http import HttpResponse
import json
 
def ajax_list(request):
    a = range(100)
    return HttpResponse(json.dumps(a), content_type='application/json')
 
def ajax_dict(request):
    name_dict = {'twz': 'Love python and Django', 'zqxt': 'I am teaching Django'}
    return HttpResponse(json.dumps(name_dict), content_type='application/json')

Django 1.7及之後到版本有更簡單的方法(使用JsonResponse(官方文檔)):

from django.http import JsonResponse
 
def ajax_list(request):
    a = range(100)
    return JsonResponse(a, safe=False)
 
def ajax_dict(request):
    name_dict = {'twz': 'Love python and Django', 'zqxt': 'I am teaching Django'}
    return JsonResponse(name_dict)

在django 1.6及之前的舊版本中能夠本身寫一個JsonResponse方法,以下:

from django.http import HttpResponse
 
import json
 
class JsonResponse(HttpResponse):
    def __init__(self,
            content={},
            mimetype=None,
            status=None,
            content_type='application/json'):
 
        super(JsonResponse, self).__init__(
            json.dumps(content),
            mimetype=mimetype,
            status=status,
            content_type=content_type)

寫好厚,咱們在urls.py中添加如下兩行:

url(r'^ajax_list/$', 'tools.views.ajax_list', name='ajax-list'),
url(r'^ajax_dict/$', 'tools.views.ajax_dict', name='ajax-dict'),

咱們訪問對應的網址會看到輸出值:

下一步就是在無刷新的狀況下把內容加載到網頁了,咱們修改一下首頁的模版index.html

<!DOCTYPE html>
<html>
<body>
<p>請輸入兩個數字</p>
<form action="/add/" method="get">
    a: <input type="text" id="a" name="a"> <br>
    b: <input type="text" id="b" name="b"> <br>
    <p>result: <span id='result'></span></p>
    <button type="button" id='sum'>提交</button>
</form>
 
 
<div id="dict">Ajax 加載字典</div>
<p id="dict_result"></p>
 
<div id="list">Ajax 加載列表</div>
<p id="list_result"></p>
 
 
<script src="http://apps.bdimg.com/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
    $(document).ready(function(){
      // 求和 a + b
      $("#sum").click(function(){
        var a = $("#a").val();
        var b = $("#b").val();
 
        $.get("/add/",{'a':a,'b':b}, function(ret){
            $('#result').html(ret);
        })
      });
 
      // 列表 list
      $('#list').click(function(){
          $.getJSON('/ajax_list/',function(ret){
            //返回值 ret 在這裏是一個列表
            for (var i = ret.length - 1; i >= 0; i--) {
              // 把 ret 的每一項顯示在網頁上
              $('#list_result').append(' ' + ret[i])
            };
          })
      })
 
      // 字典 dict
      $('#dict').click(function(){
          $.getJSON('/ajax_dict/',function(ret){
              //返回值 ret 在這裏是一個字典
              $('#dict_result').append(ret.twz + '<br>');
              // 也能夠用 ret['twz']
          })
      })
    });
</script>
</body>
</html>

技能提高:getJSON中寫的對應網址,用urls.py中的name來獲取是一個更好的方法!

標籤:{% url 'name' %}

<script>
    $(document).ready(function(){
      // 求和 a + b
      $("#sum").click(function(){
        var a = $("#a").val();
        var b = $("#b").val();
 
        $.get("{% url 'add' %}",{'a':a,'b':b}, function(ret){
            $('#result').html(ret);
        })
      });
 
      // 列表 list
      $('#list').click(function(){
          $.getJSON("{% url 'ajax-list' %}",function(ret){
            //返回值 ret 在這裏是一個列表
            for (var i = ret.length - 1; i >= 0; i--) {
              // 把 ret 的每一項顯示在網頁上
              $('#list_result').append(' ' + ret[i])
            };
          })
      })
 
      // 字典 dict
      $('#dict').click(function(){
          $.getJSON("{% url 'ajax-dict' %}",function(ret){
              //返回值 ret 在這裏是一個字典
              $('#dict_result').append(ret.twz + '<br>');
              // 也能夠用 ret['twz']
          })
      })
    });
</script>

這樣作最大的好處就是在修改urls.py中的網址後,不用改模版中對應的網址。

補充:若是是一個複雜的列表 或 字典,由於好比以下信息:

person_info_dict = [
    {"name":"laowu", "age":20},
    {"name":"wulaoer", "age":24},
    {"name":"laoer", "age":33},
]

這樣咱們遍歷列表的時候,每次遍歷獲得一個字典,再用字典的方法去處理,固然有更簡單的遍歷方法:用$.each()方法代替for循環,html代碼(jQuery)

$.getJSON('ajax-url-to-json', function(ret) {
    $.each(ret, function(i,item){
        // i 爲索引,item爲遍歷值
    });
});

最後,附上一個返回圖片並顯示的ajax實例:

Django Ajax CSRF認證

CSRF(Cross-site request forgery)跨站請求僞造,也被稱爲「one click attack」或者session riding,一般縮寫爲CSRF或者XSRF,是一種對網站的惡意利用。儘管聽起來像跨站腳本(XSS),但它與XSS很是不一樣,而且攻擊方式幾乎相左。XSS利用站點內的信任用戶,而CSRF則經過假裝來自受信任用戶的請求來利用受信任的網站。與XSS攻擊相比,CSRF攻擊每每不大流行(所以對其進行防範對資源也至關稀少)和難以防範,因此被認爲比XSS更具危險性。

Django中自帶來防止CSRF攻擊的功能,可是一些新手不知道如何使用,給本身編程帶來了麻煩。經常會出現下面Django csrf token missing or incorrect的錯誤。

GET請求不須要CSRF認證,POST請求須要正確認證才能獲得正確的返回結果。通常在POST表單中加入{% csrf_token %}

<form method="POST" action="/post-url/">
    {% csrf_token %}
     
    <input name='zqxt' value="吳老二博客Django技術">
</form>

若是使用Ajax調用的時候,就要麻煩一些。須要注意一下幾點:

一、在視圖中使用render(而不要使用render_to_response)

二、使用jQuery的ajax或者post以前加入這個js代碼:

jQuery(document).ajaxSend(function(event, xhr, settings) {
    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;
    }
    function sameOrigin(url) {
        // url could be relative or scheme relative or absolute
        var host = document.location.host; // host + port
        var protocol = document.location.protocol;
        var sr_origin = '//' + host;
        var origin = protocol + sr_origin;
        // Allow absolute or scheme relative URLs to same origin
        return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
            (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
            // or any other URL that isn't scheme relative or absolute i.e relative.
            !(/^(\/\/|http:|https:).*/.test(url));
    }
    function safeMethod(method) {
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }

    if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
        xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
    }
});

或者更爲優雅簡潔的代碼(不能寫在.js 中,要直接寫在模版文件中):

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

這樣以後,就能夠像原來同樣的使用jQuery.ajax()和jQuery.post()了

相關文章
相關標籤/搜索