程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Django的項目---管理員模塊(下)_09【可讀性更好版本】

編輯:Python

(0)摘要

# 課程鏈接:

全新 django3 入門到項目實戰(零基礎學django、項目開發實踐、大學畢業設計均可用)_哔哩哔哩_bilibili

# 課程覆蓋:

        管理員模塊_(4-11 ~~~ 4-12 的課程),其中 ajax 初識分兩節筆記


#  若無閒事掛心頭,便是人間好時節

(1)4_11 圖片驗證碼(校驗)

# (1)驗證碼校驗

                1)校驗的邏輯。我們知道不同用戶登錄時的驗證碼是不一樣的,但是我們又想要實現一對一的校驗。那麼就需要利用 session 隊列了。在 session 中,我們存放了不同用戶的憑證和 info ,也就是說在生成了驗證碼後,服務器給浏覽器返回驗證碼信息,我們可以將相應的驗證碼寫入 session 中。

                 

                要理解上面的邏輯,需要重新看一下我們寫的中間件。假設浏覽器想訪問的 url 為 /admin/list/ ,那麼一開始的時候是判斷的是否訪問裡面列表的兩個 url 不是的話,就直接看看 session 的 info 字段有沒有寫入東西,如果沒有就重定向到 /login/ 。


# (2)圖片驗證碼校驗的實現

                1)我們在生成了驗證碼後,我們把驗證碼的真值寫到 session 中,用圖中 request.session["img_code"] = code_words 來進行設置,同時我們可以為這個驗證碼設置有效時間是 60 秒,具體可以看圖中注釋。

                2)重新修改 login 的視圖函數的邏輯。由於現在用戶還要輸入驗證碼,因此在 form.cleaned_data 字典中得到的就多一個字段的數據了。(我們在鉤子方法中加入了新的驗證碼字段 verify,後面會給出源碼)。為了不妨礙後續的用戶名和密碼的判斷,我們選擇 pop 的方式從這個字典數據中取出數值,並且刪除 verify 字段,那麼這裡得到的就是用戶輸入的驗證碼 user_input_code ;然後我們再重新取出 request.session.get("img_code", "") 就是從session 隊列中取出驗證碼的真值,我們將輸入的和真值統一大寫後進行匹配,如果不一致就返回錯誤。

                 

                3)考慮到我們先前將 session 信息的有效時間設為了 60 秒,因此我們還要再設置一下 session 的有效時間,比如七天免登錄。代碼如下圖所示。我們要理解整個一個驗證的過程是一個用戶的。邏輯要轉過來。


# (3)登錄的源碼

# -*- coding=utf-8 -*-
# github: night_walkiner
# csdn: 潘迪仔
from django import forms
from app01 import models
from django.shortcuts import render, redirect, HttpResponse
from app01.utils.encrypt import md5
from app01.utils.check_words import check_code
from app01.utils.bootstrap import BootStrapForm
class LoginForm(BootStrapForm):
username = forms.CharField(
label="用戶名",
widget=forms.TextInput,
required=True
)
password = forms.CharField(
label="密碼",
widget=forms.PasswordInput,
required=True
)
verify = forms.CharField(
label="驗證碼",
widget=forms.TextInput,
required=True
)
# 鉤子方法---來判斷獲得密碼的值
def clean_password(self):
pwd = self.cleaned_data.get("password")
# 對密碼進行 md5() 加密
return md5(pwd)
def admin_login(request):
"""登錄"""
if request.method == "GET":
form = LoginForm()
context = {
"form": form,
}
return render(request, 'login.html', context)
form = LoginForm(data=request.POST)
if form.is_valid():
# cleaned_data 就是獲得的 post 數據。比如結果是 {'username': '123', 'password': '123', 'verify': xxxx}
user_input_code = form.cleaned_data.pop("verify")
img_code = request.session.get("img_code", "")
# .upper() 是可以將字符串裡面全部都大寫
if img_code.upper() != user_input_code.upper():
form.add_error("verify", "驗證碼輸入錯誤")
return render(request, 'login.html', {'form': form})
admin_info = models.Admin.objects.filter(**form.cleaned_data).first()
if not admin_info:
form.add_error("password", "用戶名或密碼錯誤")
return render(request, 'login.html', {'form': form})
# 用戶密碼校驗成功後,網站生成隨機字符串;寫到用戶浏覽器的 cookie 中;再寫入到 session 中。
# admin_info 是從數據庫中取出的。
request.session["info"] = {"id": admin_info.id, "name": admin_info.username}
# 設置 7 天免登錄
request.session.set_expiry(60 * 60 * 24 * 7)
return redirect('/admin/list/')
return render(request, 'login.html', {"form": form})
# 注銷
def admin_logout(request):
"""注銷函數"""
# 清楚當前用戶的 session 信息
request.session.clear()
# 重定向回登錄頁面
return redirect('/login/')
def check_words(request):
# 驗證碼的生成
# (1) 導入圖片驗證碼插件。
img, code_words = check_code()
# 驗證碼的校驗。每個用戶在登錄時候,肯定是對應不同的驗證碼
# 我們利用 session 每個用戶對應不同的信息,然後將各自的驗證碼放入到 session 的新增字段 img_code 中。
request.session['img_code'] = code_words
# request.session.set_expiry(x) 是用來設置驗證碼有效時間為 x 秒的
request.session.set_expiry(60)
# (2) 寫入內存(Python3)
# 其實這一步我們是要把 img 寫入輔存(磁盤),然後再從輔存取出使用的。但是我們知道cpu、內存、輔存的三者的寫入寫出關系,
# 因此為了加快這個調用邏輯,我們可以將圖片對象暫時存在內存中。那麼具體的操作如下:
from io import BytesIO # 這是操作內存的一個工具
# 實例化內存流對象
stream = BytesIO()
# (3) 使用 img.save() 存在內存流中。這裡可以理解為,保存了 stream.png 圖片,只是存在內存而已。
img.save(stream, 'png')
# (4) stream.getvalue() 就是取出保存在內存中的圖片驗證碼。其名稱就是 stream 了
return HttpResponse(stream.getvalue())

(2)4_12 初識 ajax_入門

# (1)ajax 請求

                1)在前面我們在解決浏覽器向網站發送請求時,使用的都是基於 form 表單形式的提交請求,也就是 GET、POST 兩種。這種方式雖然容易,但是每一次點擊提交的時候,都需要刷新一次頁面。

                2)除了上面的形式,我們可以基於 ajax 向後台發送請求,這種可以理解為偷偷的向服務器發送請求,也就是不刷新頁面的請求方式。這裡依賴 JQuery 庫,這是一個經典的js框架了。然後就是編寫 ajax 代碼。 

                 

                下面是 ajax 請求代碼的注釋。

// 使用了 python 的注釋方式。。。
$.ajax({
url: "請求的地址", # 這裡是請求的地址
type: "get", # 這是請求的類型是 get 還是 post
data: { # 如果是 get 請求的話,那麼 data 就是傳到後台的參數
n1: 123,
n2: 456
},
# 如果請求成功了,後端就會返回一個 res 參數,然後我們可以直接獲取到
success:function(res){
console.log(res)
}
})

               


# (2)JavaScript 相關知識_基於 Dom 方式的綁定點擊事件

                1)基於 Dom 方式的綁定點擊事件。即形如下圖所示的方法。(該頁面是 task_list.html ,我們已經定義了相關的視圖函數。)

                 那麼執行上述代碼後,我們可以通過點擊前端頁面的點擊按鈕,就可以在控制台(浏覽器的)輸出一次點擊了按鈕。

               

                2)如果我們想要點擊的時候,發送一個請求,就需要修改 js 的代碼。在此之前,我們提前創建一個 url 為 "/task/ajax/"。並且給出的響應值是 "接收成功了",然後我們開始按照上面 ajax 請求的格式和注釋,來修改 js 的代碼。如下圖所示。【url 的地方有個坑,具體看後面我填坑】

                然後我們測試點擊按鈕,可以看到返回值 res :"接收成功啦"。

                 

                我們可以查看請求時候的 url,如下圖所示 

                 

                當然,我們也可以在後台的視圖函數,即 task_ajax (就是我們所請求的那個 url)

獲得 get 請求傳來的參數。如下圖的代碼所示。

                3)如果我們的 ajax 使用的是 post 請求,也就是在上面的代碼中,將 type: "get" 改成 type: "post" ,再次回到前端頁面按點擊就會報錯。

                如何免除 csrf_token 認證,這裡有個知識點。就是導入如下的包,如何在函數前引用。這是因為我們之前

                我自己也補充一個知識點,post 請求後,我們也可能出現下面的問題,即狀態碼是500 的,這是因為我們在 ajax 代碼上的 url: "/task/ajax" 是不可以的,需要改成 url: "/task/ajax/"。

                於是,在前面兩個問題解決後,我們再次點擊按鈕,顯示了接收成功。

                 

                這樣,我們就可以使用 post 請求的參數了。


# (3)JavaScript 相關知識_基於 JQuery 方式的綁定點擊事件

                1)基於 JQuery 方式的綁定點擊事件。即形如下面的方式的。就是我們將原來的 onclick 屬性給去掉,利用 id 屬性來綁定事件。然後 js 代碼塊中,按照格式 $(function () { 函數體 }) 的格式來寫 js 代碼,那麼這種寫法的話,當頁面加載完成後會自動執行函數體的內容。

                2)因此,我們利用自動加載內容,我們定義一個綁定事件的函數 bindBtn1Event(),定義的方式是 function 函數名() { 函數體 }, 那麼這個函數的函數體內容就是頁面加載完成後會去找到 id 綁定的按鈕,也就是一旦發生了點擊後,就會執行click()裡面的 ajax 內容。


# (4)Json 格式

                1)如果我們使用 JQuery 的方式做 ajax 請求的話,一般情況下,後台不會以頁面返回,而是以 json 格式返回數據。舉個例子來說,比如我們 python 後端生成的一個字典准備返回前端,但是這裡還需要進行 json 化數據。具體方法見下例。之所以 json 化是因為以 json 格式傳回前端能夠讓前端對這些數據進一步的操作。

                當然,我們也可以利用 Django 內置的一種方法來寫,即使用 JsonResponse 來返回,那麼寫法就是下圖這樣。這種方法是自動的轉換,上面的是我們手動轉換。

                2)我們將 json 格式內容返回到前端之後,那麼實際上返回的是一個字符串,因此前端要對這個 json 格式數據反序列化成 js 裡面的對象。這裡我們就需要在 ajax 中新增一個對象。 

                 

                然後我們就可以取後台返回的數據的值了。那麼代碼如下:

                我們到前端去觸發點擊事件,就可以看到控制台輸出了我們先前定義的 status 和 data 字段分布對應的值了。其實對於 ajax 而言,其內部返回和處理的數據格式都是 json 格式。


# (5)實例 2 ,將前端的 input 的內容返回到後端。(利用 ajax)

                1)問題就是我們要將前台的輸入框裡面的值,通過 ajax 請求發送到後台。那麼我們在前端添加了相應的輸入框後,然後設置新的點擊事件。首先是新增的 html 代碼。

                基於上面的 ajax 代碼,我們有如下的代碼。首先是,我們如果想在 ajax 代碼中,獲取輸入框的內容,可以利用他們的 id 值來進行類似索引的效果。即 $("#id值").val() 來獲取,那麼 $("#id值") 是獲取到對應的 id 的輸入框,.val() 方法就是獲取這個輸入框的內容。

                然後我們打開前端頁面,在輸入框輸入內容,當觸發了點擊按鈕後,成功獲取到了內容並且傳到了後台。 


# (6)實例3,如果輸入框有很多的情況

                1)如果輸入 框有很多的情況下,我們可以用 form 標簽將這些輸入的標簽包裹起來。那麼這個時候裡面的 input 標簽就可以不用考慮 id 屬性了,但是必須要有 name 屬性。而 form 標簽必須設置 id 屬性。【最後的那個 input 的 id = "btn3",忘記改了】

                2)然後修改 ajax 的代碼,如下圖所示,紅框中的代碼,$("#form3").serialize() 就可以將 form 內的 input 標簽的內容全部獲得並且打包作為數據,以發送到後台。

                3)那麼我們測試了之後,得到下圖的結果。顯然是可以的 


(3)4_12 初識 ajax_小案例實戰

# (1)案例實戰

                1)數據庫表創建。下圖是創建任務列表的數據庫表的代碼。對於 level_choices 以及外鍵的相關知識這個,可以去看員工表的那一節有講解。我們設計好表結構,然後執行遷移命令即可。

                2)使用 ModelForm 來渲染前端。前端的代碼如下,我們也添加了相應的樣式控制的代碼。

                頁面效果顯示。


# (2)案例實現的測試。

                1)前端的 html 代碼。

                2)基於 JQuery 的代碼。這裡記得復習下上面的,邏輯就是頁面渲染完後,自動執行代碼,如果用戶觸發了綁定的事件,就執行相應的代碼。

                3)視圖函數的編寫,這裡是初步測試的。

                4)初步結果查看。

               

                前端接收的返回值,即 res.status


# (3)案例完善,添加數據校驗和錯誤信息

                1)數據校驗功能。

                2)錯誤信息的問題。我們知道 form.errors 裡面包含了所有的錯誤信息,如果提交的數據是有問題的,那麼我們可以使用 forms.errors.as_json() 就能以 json 的格式傳回前端。

                那麼前端傳回的 json 數據如下:

                 實際上使用了 as_json() 方法傳回的錯誤信息,不是很好閱讀,因此我們取消掉這個,也就是上面代碼 form.errors.as_json() 變為 form.errors,就能看到返回的錯誤信息更加方便閱讀了。

                3)顯示錯誤的前端 html 代碼如下,

                4)js 代碼如下,見紅框的注釋。$("id_" + name) 是索引到這個 id 值對應的標簽,那麼 $("id_" + name).next() 就是該標簽的下一個標簽,然後 $("id_" + name).next().text() 就是下一個標簽的內容。之所以是 data[0] ,是因為傳回來的錯誤信息是個列表。

                5)錯誤信息的視圖函數


【補充知識】

# (1)models.py 數據表中的 models.TextField(versbose_name="")

               

                這個數據庫定義的方式,就是存儲文本的。如果我們使用 ModelForm() 來渲染的話,默認的樣式 widgets = { "detail": forms.Textarea },然後前端的頁面就是下圖這樣的。

                如果我們想要改變成普通的輸入框類型,那麼我們也可以通過設置 widgets 來實現。但是需要導入 forms 模塊。那麼類的定義就變為這樣,見紅框處,即 widgets = { "detail": forms.TextInput }

                結果如圖所示:


# (2)models.py 下如果涉及到外鍵的話,如何取到外鍵的值,而不是取對象。

                就是如下圖所示,負責人其實是對應的 Admin 表,因此我們要使用 __str__ 方法。

                要解決這個問題,就需要去 Admin 表中,寫一個方法,即如下的代碼。

                結果如下:



  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved