(轉)python 全棧開發,Day75(Django與Ajax,檔案上傳,ajax傳送json資料,基於Ajax的檔案上傳,SweetAlert外掛)
昨日內容回顧
基於物件的跨表查詢 正向查詢:關聯屬性在A表中,所以A物件找關聯B表資料,正向查詢 反向查詢:關聯屬性在A表中,所以B物件找A物件,反向查詢 一對多: 按欄位:xx book ------------------ > publish <-------------------- 按表名小寫__欄位名。比如publish__name 多對多: 正 按欄位:xx bookView Code------------------------- > author <------------------------- 反 按表名小寫__欄位名 一對一 正 按欄位:.ad author ------------------------- > authordetail <------------------------- 反 按表名小寫 authordetail_obj.author
一、Django與Ajax
AJAX準備知識:JSON
什麼是 JSON ?
- JSON 指的是 JavaScript 物件表示法(JavaScript Object Notation)
- JSON 是輕量級的文字資料交換格式
- JSON 獨立於語言 *
- JSON 具有自我描述性,更易理解
* JSON 使用 JavaScript 語法來描述資料物件,但是 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;} // 不能使用函式和日期物件 }
json支援7種資料格式
python 原始型別向 json 型別的轉化對照表:
Python | JSON |
dict | object |
list, tuple | array |
str, unicode | string |
int, long, float | number |
True | true |
False | false |
None | null |
stringify與parse方法
JavaScript中關於JSON物件和字串轉換的兩個方法:
JSON.parse(): 用於將一個 JSON 字串轉換為 JavaScript 物件
JSON.parse('{"name":"Q1mi"}'); JSON.parse('{name:"Q1mi"}') ; // 錯誤 JSON.parse('[18,undefined]') ; // 錯誤
JSON.stringify(): 用於將 JavaScript 值轉換為 JSON 字串。
JSON.stringify({"name":"Q1mi"})
和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>View Code
用JSON表示如下:
{ "name": "中國", "province": [{ "name": "黑龍江", "cities": { "city": ["哈爾濱", "大慶"] } }, { "name": "廣東", "cities": { "city": ["廣州", "深圳", "珠海"] } }, { "name": "臺灣", "cities": { "city": ["臺北", "高雄"] } }, { "name": "新疆", "cities": { "city": ["烏魯木齊"] } }] }View Code
由上面的兩端程式碼可以看出,JSON 簡單的語法格式和清晰的層次結構明顯要比 XML 容易閱讀,並且在資料交換方面,由於 JSON 所使用的字元要比 XML 少得多,可以大大得節約傳輸資料所佔用得頻寬。
Ajax簡介
AJAX(Asynchronous Javascript And XML)翻譯成中文就是“非同步Javascript和XML”。即使用Javascript語言與伺服器進行非同步互動,傳輸的資料為XML(當然,傳輸的資料不只是XML,現在更多使用json資料)。
- 同步互動:客戶端發出一個請求後,需要等待伺服器響應結束後,才能發出第二個請求;
- 非同步互動:客戶端發出一個請求後,無需等待伺服器響應結束,就可以發出第二個請求。
AJAX除了非同步的特點外,還有一個就是:瀏覽器頁面區域性重新整理;(這一特點給使用者的感受是在不知不覺中完成請求和響應過程)
應用情景
搜尋引擎根據使用者輸入的關鍵字,自動提示檢索關鍵字。
還有一個很重要的應用場景就是註冊時候的使用者名稱的查重。
其實這裡就使用了AJAX技術!當檔案框發生了輸入變化時,使用AJAX技術向伺服器傳送一個請求,然後伺服器會把查詢到的結果響應給瀏覽器,最後再把後端返回的結果展示出來。
- 整個過程中頁面沒有重新整理,只是重新整理頁面中的區域性位置而已!
- 當請求發出後,瀏覽器還可以進行其他操作,無需等待伺服器的響應!
比如部落格園的註冊頁面:
https://account.cnblogs.com/
直接點選註冊,相關的輸入框就會有提示。這些就是利用區域性重新整理做到的!
輸入框綁定了blur事件(當輸入完使用者名稱以後觸發動作)
優點:
- AJAX使用Javascript技術向伺服器傳送非同步請求
- AJAX無須重新整理整個頁面
簡單來說,1.非同步請求。2.區域性重新整理
Ajax流程圖
1、客戶端觸發非同步操作
2、建立新的XMLHttpRequest物件,這是ajax的核心(需要著重的學習下)
3、通過send()方法實現與server的連線4
4、伺服器端接收請求,並處理
5、返回處理的結果,這個結果可以是XML文件、也可以是josn字串(一般情況下josn就可以處理大部分的結果、而且相對的比較好操作)
6、在客戶端去接收伺服器傳回來的結果,並且通過javascript進行你想要的處理
發請求給伺服器的途徑:
1. 位址列:get
2. form表單,支援get和post
3. 超連結 <a href="/path/">click</a> 這種是get方式
4. Ajax請求: 可以指定get和post
發Ajax請求一般返回httpResponse()
案例
滑鼠點選事件
效果:當點選click時,彈出提示框
準備工作:
使用Pycharm新建專案ajaxDemo
修改urls.py,增加路徑index
from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), ]View Code
修改views.py,增加index檢視函式
def index(request): return render(request,"index.html")View Code
在建立index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script scr="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> </head> <body> <button id="btn">click</button> <script> $("#btn").click(function () { alert(123) }) </script> </body> </html>View Code
啟動django專案,訪問url:http://127.0.0.1:8000/index/
點選click,就會出現彈框
簡單的ajax請求
效果:當點選click時,按鈕底部出現一本書名
修改urls.py,增加books路徑
urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), path('books/', views.books), ]View Code
修改books檢視函式
def books(request): return HttpResponse("群山淡景")View Code
修改index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> </head> <body> <button id="btn">click</button> <p class="con"></p> <script> $("#btn").click(function () { //傳送ajax請求 $.ajax({ url:"/books/", //請求的url type:"get", //預設get success:function (data) { //data接收響應體,必須要有 console.log(data); //列印響應體資料 $(".con").text(data); //修改p標籤的text值 } }) }) </script> </body> </html>View Code
訪問url:點選click按鈕,底部出現一本書
那麼,它經歷了怎樣的過程呢?請參考上面的ajax流程圖!
success表示請求成功,並拿到響應體之後,執行的動作!data是用來接收響應體的資料。data這個命令可以隨便定義,約定成俗,使用data!
它接收HttpResponse,比如:《群山淡景》
最後是dom操作,修改HTML程式碼,實現了局部重新整理!
ajax加法運算(get請求)
頁面輸入兩個整數,通過AJAX傳輸到後端計算出結果並返回。
修改urls.py,增加cal路徑
urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), path('books/', views.books), path('cal/', views.cal), ]View Code
修改views.py,增加cal檢視函式
def cal(request): a = request.GET.get("a") #獲取第一個值,型別為字串 b = request.GET.get("b") #獲取第二個值 res = int(a) + int(b) # 必須要轉換為數字才能計算 return HttpResponse(str(res)) # HttpResponse只能接收字串View Code
修改index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <style type="text/css"> input { width: 50px; } </style> </head> <body> <input type="text" id="n1"> + <input type="text" id="n2"> = <input type="text" id="result"> <button id="cal">計算</button> <script> $("#cal").click(function () { var n1 = $("#n1").val(); var n2 = $("#n2").val(); //傳送ajax請求 $.ajax({ url: "/cal/", //請求的url type: "get", //預設get data: { a: n1, b: n2 }, success: function (data) { //data接收響應體,必須要有 console.log(data); //列印響應體資料 $("#result").val(data); //修改p標籤的text值 } }) }) </script> </body> </html>View Code
訪問url:http://127.0.0.1:8000/index/
效果如下:
模擬停頓
先點選click,在輸出數字進行計算。等待5秒後,出現書籍!
編輯views.py,匯入time模組,修改books檢視函式
from django.shortcuts import render,HttpResponse import time # Create your views here. def index(request): return render(request,"index.html") def books(request): time.sleep(5) return HttpResponse("群山淡景") def cal(request): a = request.GET.get("a") #獲取第一個值,型別為字串 b = request.GET.get("b") #獲取第二個值 res = int(a) + int(b) # 必須要轉換為數字才能計算 return HttpResponse(str(res)) # HttpResponse只能接收字串View Code
修改index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <style type="text/css"> input { width: 50px; } </style> </head> <body> <button id="btn">click</button> <p class="con"></p> <hr> <input type="text" id="n1"> + <input type="text" id="n2"> = <input type="text" id="result"> <button id="cal">計算</button> <script> $("#btn").click(function () { //傳送ajax請求 $.ajax({ url:"/books/", //請求的url type:"get", //預設get success:function (data) { //data接收響應體,必須要有 console.log(data); //列印響應體資料 $(".con").text(data); //修改p標籤的text值 } }) }); $("#cal").click(function () { var n1 = $("#n1").val(); var n2 = $("#n2").val(); //傳送ajax請求 $.ajax({ url: "/cal/", //請求的url type: "get", //預設get data: { a: n1, b: n2 }, success: function (data) { //data接收響應體,必須要有 console.log(data); //列印響應體資料 $("#result").val(data); //修改p標籤的text值 } }) }); </script> </body> </html>View Code
重新整理頁面,先點選click,在輸入數值,最後點選計算。
效果如下:等待5秒,出現書籍
ajax加法運算(post請求)
更改cal檢視函式,改為post接收資料
def cal(request): a = request.POST.get("a") #獲取第一個值,型別為字串 b = request.POST.get("b") #獲取第二個值 res = int(a) + int(b) # 必須要轉換為數字才能計算 return HttpResponse(str(res)) # HttpResponse只能接收字串View Code
更改index.html,ajax改為post請求
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <style type="text/css"> input { width: 50px; } </style> </head> <body> <input type="text" id="n1"> + <input type="text" id="n2"> = <input type="text" id="result"> <button id="cal">計算</button> <script> $("#cal").click(function () { var n1 = $("#n1").val(); var n2 = $("#n2").val(); //傳送ajax請求 $.ajax({ url: "/cal/", //請求的url type: "post", //預設get data: { a: n1, b: n2 }, success: function (data) { //data接收響應體,必須要有 console.log(data); //列印響應體資料 $("#result").val(data); //修改p標籤的text值 } }) }); </script> </body> </html>View Code
重新整理頁面,重新計算。發現沒有反應,開啟瀏覽器控制檯-->network
檢視響應頁面,這個頁面看著熟悉吧。被django的csrf模組攔截了!
那麼如何解決這個問題呢?
1. 直接修改settings.py,註釋掉csrf模組
2. post提交時,帶上鍵值為csrfmiddlewaretoken的資料
第一種方案,顯然不是我們想要的。我們選擇第二種方案!
修改index.html,增加
{% csrf_token %}
完整程式碼如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <style type="text/css"> input { width: 50px; } </style> </head> <body> <input type="text" id="n1"> + <input type="text" id="n2"> = <input type="text" id="result"> <button id="cal">計算</button> {% csrf_token %} <script> $("#cal").click(function () { var n1 = $("#n1").val(); var n2 = $("#n2").val(); //傳送ajax請求 $.ajax({ url: "/cal/", //請求的url type: "post", //預設get data: { a: n1, b: n2 }, success: function (data) { //data接收響應體,必須要有 console.log(data); //列印響應體資料 $("#result").val(data); //修改p標籤的text值 } }) }); </script> </body> </html>View Code
重新整理頁面,使用瀏覽器控制檯,檢視html程式碼
發現有一個input標籤,name名為csrfmiddlewaretoken。後面有一個value值,這個是django生成的。每次重新整理頁面,它會變動!
我們不可能像爬蟲一樣,把這個value給爬下來!終極辦法就是通過dom來獲取input的值
通過屬性選擇器,可以精確的查找出input的值
$("[name=csrfmiddlewaretoken]")[0]
使用console來模擬dom操作
獲取value值,使用val()
注意:在html標籤裡面, 只有input,select,textarea 這3個標籤是用val拿值
修改index.html,增加引數csrfmiddlewaretoken
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <style type="text/css"> input { width: 50px; } </style> </head> <body> <input type="text" id="n1"> + <input type="text" id="n2"> = <input type="text" id="result"> <button id="cal">計算</button> {% csrf_token %} <script> $("#cal").click(function () { var n1 = $("#n1").val(); var n2 = $("#n2").val(); var csrf = $("[name=csrfmiddlewaretoken]").val(); //傳送ajax請求 $.ajax({ url: "/cal/", //請求的url type: "post", //預設get data: { a: n1, b: n2, csrfmiddlewaretoken:csrf, }, success: function (data) { //data接收響應體,必須要有 console.log(data); //列印響應體資料 $("#result").val(data); //修改p標籤的text值 } }) }); </script> </body> </html>View Code
重新整理頁面,再次計算,就可以正常使用了!
基於Ajax進行登入驗證
一般情況下,通常會將表單之類的標籤放到form標籤裡面。這裡我們使用form,只是把它當成一個容器而已!不使用submit按鈕提交,而是使用ajax提交!使用div容器也是可以的!
注意點:
1. 不寫action,預設用當前的url
2.botton標籤放到form標籤之後,它具有sumbit功能!它和submit效果是一樣的,會重新整理頁面!
那麼需要使用按鈕怎麼辦?在input裡面,有一個type="button"的。它有按鈕效果,點選之後,沒有任何反應!它在form表單裡面,是安全的!沒有預設事件!
那麼它和ajax結合,就能實現某些功能。比如傳送ajax請求!
修改index.html
注意:只要頁面裡面有下面的程式碼就可以,無論放到哪個位置都可以!只要jquery能獲取到就行!
每次post提交,必須傳送key為csrfmiddlewaretoken的值,否則提示403
這個是django給你發的身份證,如果沒有身份證,那麼django就會攔截
{% csrf_token %}
準備工作:準備一張表user
修改models.py,增加user表模型
from django.db import models # Create your models here. class User(models.Model): user=models.CharField(max_length=32) pwd=models.CharField(max_length=32)View Code
使用下面2個命令生成表
python manage.py makemigrations
python manage.py migrate
插入2條資料,注意修改表名
INSERT INTO app01_user (id, user, pwd) VALUES (1, 'xiao', 123); INSERT INTO app01_user (id, user, pwd) VALUES (2, 'zhang', 123);View Code
修改urls.py,增加login路徑
urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), path('books/', views.books), path('cal/', views.cal), path('login/', views.login), ]View Code
HttpResponse必須是一個字串,因此想要返回一個字典,必須使用json序列化才行
修改views.py,增加login,完整程式碼如下:
from django.shortcuts import render,HttpResponse from app01.models import User import time import json # Create your views here. def index(request): return render(request,"index.html") def books(request): time.sleep(5) return HttpResponse("群山淡景") def cal(request): a = request.POST.get("a") #獲取第一個值,型別為字串 b = request.POST.get("b") #獲取第二個值 res = int(a) + int(b) # 必須要轉換為數字才能計算 return HttpResponse(str(res)) # HttpResponse只能接收字串 def login(request): user = request.POST.get("user") pwd = request.POST.get("pwd") #根據表單的使用者名稱和密碼到資料庫中匹配 user_obj = User.objects.filter(user=user, pwd=pwd).first() #一般請求下,需要定義一個字典。msg是約定成俗的名字,用來做提示的 response = {"user":None,"msg":None} if user_obj: # 判斷有返回結果的請求下 response["user"] = user_obj.user # 修改字典的使用者名稱 else: response["msg"] = "使用者名稱或者密碼不一致" # 修改提示資訊 #返回json格式資料,預設序列化時,對中文預設使用的ascii編碼。 # ensure_ascii=False表示顯示真正的中文 return HttpResponse(json.dumps(response, ensure_ascii=False))View Code
修改index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <style type="text/css"> input { width: 50px; } </style> </head> <body> {% csrf_token %} <h4>登入驗證</h4> <form> <lable>使用者名稱</lable><input type="text" id="user"> <lable>密碼</lable><input type="password" id="pwd"> <input type="button" value="提交" id="login_btn"> {#顯示錯誤資訊#} <span class="error"></span> </form> {% csrf_token %} <script> $("#login_btn").click(function () { var csrf = $("[name=csrfmiddlewaretoken]").val(); //傳送ajax請求 $.ajax({ url: "/login/", //請求的url type: "post", //預設get data: { user: $("#user").val(), pwd: $("#pwd").val(), csrfmiddlewaretoken:csrf, }, success: function (data) { //data接收響應體,必須要有 console.log(data); //列印響應體 console.log(typeof data); //列印資料型別 var data=JSON.parse(data); //反序列化資料 if(data.user){ // 登陸成功 //window.location.href表示跳轉頁面 alert("登入成功");window.location.href="/index/"; } else{ // 登陸失敗 //修改span標籤,顯示失敗的返回值,並顯示紅色,左間距20px $(".error").text(data.msg).css({"color":"red","margin-left":"20px"}) //設定定時器,2秒後清空提示資訊 setTimeout(function () { $(".error").text("") //清空提示資訊 },2000) } } }) }); </script> </body> </html>View Code
注意:ajax裡面的success接收的data響應體,必須要JSON.parse反序列才行
訪問頁面:http://127.0.0.1:8000/index/
效果如下:
ajax還有其他引數,可以設定,如下:
<button class="send_Ajax">send_Ajax</button> <script> $(".send_Ajax").click(function(){ $.ajax({ url:"/handle_Ajax/", type:"POST", data:{username:"Yuan",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>View Code
響應錯誤時,會執行error中的程式碼。
當 AJAX 請求正在進行時,執行complete的程式碼。
它可以做一個請求等待的效果!
二、檔案上傳
請求頭ContentType
ContentType指的是請求體的編碼型別,常見的型別共有3種:
1. application/x-www-form-urlencoded
這應該是最常見的 POST 提交資料的方式了。瀏覽器的原生 <form> 表單,如果不設定 enctype
屬性,那麼最終就會以 application/x-www-form-urlencoded 方式提交資料。請求類似於下面這樣(無關的請求頭在本文中都省略掉了):