Django傳遞數據給JS
有時候我們想把一個list或者dict傳遞給javascript,處理后顯示到網頁上,比如要用js進行可視化到數據。
請注意:如果是不處理,直接顯示在網頁上,用Django模版就可以了,請看前面的教程。
這里講述兩種方法:
一、頁面加載完成后,在頁面上操作,在頁面上通過ajax方法得到新的數據(再向服務器發送一次請求)並顯示在網頁上,在這種情況適用於頁面不刷新的情況下,動態加載一些內容。比如用戶輸入一個值或者點擊某個地方,動態地把相應內容顯示在網頁上。
這種請詳見下面Django Ajax一節的內容。
二、直接在視圖函數(views.py中的函數)中渲染一個list或dict的內容,和網頁其它部分一起顯示到網頁上(一次性地渲染,還是同一次請求)。
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中的一部分
<script type="text/javascript"> var List = {{ List }}; alert(List); </script>
需要注意的是,我們如果直接這么做,傳遞到js的時候,網頁的內容會被轉義得到的格式會報錯。訪問時會得到Uncaught SyntaxError: Unexpected token ILLEGAL
需要注意兩點:
1、views.py中返回的函數中的值要用json.dumps()處理
2、在網頁上要加一個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調用的時候,就要麻煩一些。需要注意一下幾點:
1、在視圖中使用render(而不要使用render_to_response)
2、使用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()了