1. 程式人生 > >(轉)python 全棧開發,Day75(Django與Ajax,檔案上傳,ajax傳送json資料,基於Ajax的檔案上傳,SweetAlert外掛)

(轉)python 全棧開發,Day75(Django與Ajax,檔案上傳,ajax傳送json資料,基於Ajax的檔案上傳,SweetAlert外掛)

昨日內容回顧

基於物件的跨表查詢

    正向查詢:關聯屬性在A表中,所以A物件找關聯B表資料,正向查詢
    反向查詢:關聯屬性在A表中,所以B物件找A物件,反向查詢
    
    一對多:
    
           按欄位:xx
    book  ------------------ >  publish
          <--------------------
          按表名小寫__欄位名。比如publish__name
    

    多對多:
    
          正 按欄位:xx
    book  
------------------------- > author <------------------------- 反 按表名小寫__欄位名 一對一 正 按欄位:.ad author ------------------------- > authordetail <------------------------- 反 按表名小寫 authordetail_obj.author
View Code

 

一、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簡介

AJAXAsynchronous Javascript And XML)翻譯成中文就是非同步JavascriptXML”。即使用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 方式提交資料。請求類似於下面這樣(無關的請求頭在本文中都省略掉了):