Python後臺開發(第三章: Django高階)

CSDN學院發表於2020-01-11

Python後臺開發(第三章: Django高階)

1 Cookie

1.1 Cookie機制

在程式中,會話跟蹤是很重要的事情。理論上,一個使用者的所有請求操作都應該屬於同一個會話,而另一個使用者的所有請求操作則應該屬於另一個會話,二者不能混淆。例如,使用者A在超市購買的任何商品都應該放在A的購物車內,不論是使用者A什麼時間購買的,這都是屬於同一個會話的,不能放入使用者B或使用者C的購物車內,這不屬於同一個會話。

而Web應用程式是使用HTTP協議傳輸資料的。HTTP協議是無狀態的協議。一旦資料交換完畢,客戶端與伺服器端的連線就會關閉,再次交換資料需要建立新的連線。這就意味著伺服器無法從連線上跟蹤會話。即使用者A購買了一件商品放入購物車內,當再次購買商品時伺服器已經無法判斷該購買行為是屬於使用者A的會話還是使用者B的會話了。要跟蹤該會話,必須引入一種機制。

Cookie就是這樣的一種機制。它可以彌補HTTP協議無狀態的不足。在Session出現之前,基本上所有的網站都採用Cookie來跟蹤會話Cookie通過在客戶端記錄資訊確定使用者身份。

1.2 什麼是Cookie

  • cookie是儲存在使用者瀏覽器端的鍵值對
  • Cookie是由伺服器生成,儲存在瀏覽器中的鍵值對資料
  • 每個域名的Cookie相互獨立
  • 瀏覽器訪問域名為A的url地址,會把A域名下的Cookie一起傳遞到伺服器
  • Cookie可以設定過期時間,預設為None,即關閉當前瀏覽器,Cookie立即清除.
  • 儲存站點的使用者資料.

1.3 Cookie原理

在這裡插入圖片描述

在這裡插入圖片描述

Cookie實際上是一小段的文字資訊。客戶端請求伺服器,如果伺服器需要記錄該使用者狀態,就使用response向客戶端瀏覽器頒發一個Cookie。客戶端瀏覽器會把Cookie儲存起來。當瀏覽器再請求該網站時,瀏覽器把請求的網址連同該Cookie一同提交給伺服器。伺服器檢查該Cookie,以此來辨認使用者狀態。伺服器還可以根據需要修改Cookie的內容。

1.4 Cookie屬性

1.4.1 屬性表

屬性 說明
set_cookie(常用) 設定Cookie的值 max_age: 預設為None
COOKIES.get(常用) 獲取Cookie的值
String name 該Cookie的名稱。Cookie一旦建立,名稱便不可更改
Object value 該Cookie的值。如果值為Unicode字元,需要為字元編碼。如果值為二進位制資料,則需要使用BASE64編碼
int maxAge 該Cookie失效的時間,單位秒。如果為正數,則該Cookie在maxAge秒之後失效。如果為負數,該Cookie為臨時Cookie,關閉瀏覽器即失效,瀏覽器也不會以任何形式儲存該Cookie。如果為0,表示刪除該Cookie。預設為–1
boolean secure 該Cookie是否僅被使用安全協議傳輸。安全協議。安全協議有HTTPS,SSL等,在網路上傳輸資料之前先將資料加密。預設為false
String path 該Cookie的使用路徑。如果設定為“/sessionWeb/”,則只有contextPath為“/sessionWeb”的程式可以訪問該Cookie。如果設定為“/”,則本域名下contextPath都可以訪問該Cookie。注意最後一個字元必須為“/”
String domain 可以訪問該Cookie的域名。如果設定為“.google.com”,則所有以“google.com”結尾的域名都可以訪問該Cookie。注意第一個字元必須為“.”
String comment 該Cookie的用處說明。瀏覽器顯示Cookie資訊的時候顯示該說明
int version 該Cookie使用的版本號。0表示遵循Netscape的Cookie規範,1表示遵循W3C的RFC 2109規範

1.4.2 程式碼例項

1.4.2.1 set_cookie

  1. url配置
re_path('set_cookie/(.+)/(.+)',views.set_cookie_handler,name='set_cookie') 
  1. views配置
def set_cookie_handler(request,key,value): 
    response = HttpResponse() 
    #max_age=60\*60 表示Cookie的有效時間3600秒,即1小時 
    response.set_cookie(key,value,max_age= 60 * 60) 
    return response 

1.4.2.2 COOKIES.get

  1. url配置
re_path('get_cookie/(.+)',views.get_cookie_handler,name='get_cookie')
  1. views配置
def get_cookie_handler(request,key): 
    value = request.COOKIES.get(key) 
    return HttpResponse(value)

注:在測試cookie之前,需要先對Django專案執行遷移,才可以在資料庫中得到對應的操作表。

1.4.3 Cookie的刪除和修改

  • Cookie並不提供修改、刪除操作。如果要修改某個Cookie,只需要新建一個同名的Cookie,新增到response中覆蓋原來的Cookie。
  • 如果要刪除某個Cookie,只需要新建一個同名的Cookie,並將maxAge設定為0,並新增到response中覆原來的Cookie。注意是0而不是負數。負數代表其他的意義。
  • 注意:修改、刪除Cookie時,新建的Cookie除value、maxAge之外的所有屬性,例如name、path、domain等,都要與原Cookie完全一樣。否則,瀏覽器將視為兩個不同的Cookie不予覆蓋,導致修改、刪除失敗。

1.4.4 Cookie的域名

  • Cookie是不可跨域名的。域名www.google.com頒發的Cookie不會被提交到域名www.baidu.com去。這是由Cookie的隱私安全機制決定的。隱私安全機制能夠禁止網站非法獲取其他網站的Cookie。
  • 正常情況下,同一個一級域名下的兩個二級域名如www.helloweenvsfei.com和images.helloweenvsfei.com也不能互動使用Cookie,因為二者的域名並不嚴格相同。如果想所有helloweenvsfei.com名下的二級域名都可以使用該Cookie,需要設定Cookie的domain引數,例如:
Cookie cookie = new Cookie("time","20080808"); 
// 新建Cookie cookie.setDomain(".helloweenvsfei.com");          
// 設定域名 cookie.setPath("/");                              
// 設定路徑 cookie.setMaxAge(Integer.MAX_VALUE);               
// 設定有效期 response.addCookie(cookie);                       
// 輸出到客戶端 
  • 可以修改本機C:\WINDOWS\system32\drivers\etc下的hosts檔案來配置多個臨時域名,然後使用setCookie.jsp程式來設定跨域名Cookie驗證domain屬性。
  • 注意:domain引數必須以點(".")開始。另外,name相同但domain不同的兩個Cookie是兩個不同的Cookie。如果想要兩個域名完全不同的網站共有Cookie,可以生成兩個Cookie,domain屬性分別為兩個域名,輸出到客戶端。

1.4.5 Cookie的安全性

  1. Cookie是儲存在客戶端,即瀏覽器的,所有具有不安全性
  2. 對於敏感的資料,應該加密,或者儲存在服務端

2 Session

2.1 Session機制

除了使用Cookie,Web應用程式中還經常使用Session來記錄客戶端狀態。Session是伺服器端使用的一種記錄客戶端狀態的機制,使用上比Cookie簡單一些,相應的也增加了伺服器的儲存壓力。

2.2 什麼是Session

  • session是儲存在伺服器端的鍵值對。
  • Session基於Cookie的。
  • Session把敏感的資料以加密的方式儲存在伺服器。
  • Session預設的過期時間是兩週,如果自己設定了過期時間,這樣自己設定的優先順序就會高於預設的
  • Session是另一種記錄客戶狀態的機制,不同的是Cookie儲存在客戶端瀏覽器中,而Session儲存在伺服器上。客戶端瀏覽器訪問伺服器的時候,伺服器把客戶端資訊以某種形式記錄在伺服器上。這就是Session。客戶端瀏覽器再次訪問時只需要從該Session中查詢該客戶的狀態就可以了。如果說Cookie機制是通過檢查客戶身上的“通行證”來確定客戶身份的話,那麼Session機制就是通過檢查伺服器上的“客戶明細表”來確認客戶身份。Session相當於程式在伺服器上建立的一份客戶檔案,客戶來訪的時候只需要查詢客戶檔案表就可以了。

2.3 Session原理

在這裡插入圖片描述

2.4 Session常用方法

屬性 說明
session[key] = value 設定Session的值 設定過期時間,預設為2周: session.set_expiry(60*60)
session.get(key) 獲取Session的值,如果沒有這個key,返回None
flush() 刪除表資料
clear() 清空sessionId對應的資料

2.5 程式碼例項

2.5.1 設定

  1. url配置
re_path('set_session/(.+)/(.+)',views.set_session_handler,name='set_session'), 
  1. views配置
def set_session_handler(request,key,value):
    request.session[key] = value 
    #設定過期時間 
    request.session.set_expiry(60 * 60) 
    return HttpResponse('設定成功') 

2.5.2 獲取

1.url配置

re_path('get_session/(.+)',views.get_session_handler,name='get_session'), 

2.views配置

def get_session_handler(request,key): 
    value = request.session.get(key) 
    return HttpResponse(value) 

2.5.3 刪除

  1. url配置
path('flush',views.flush_session_handler,name='flush'), 

  1. views配置
def flush_session_handler(request): 
    request.session.flush()

2.5.4 clear

  1. url配置
path('clear',views.clear_session_handler,name='clear'),

  1. views配置
def clear_session_handler(request): 
    request.session.clear() 
    return HttpResponse('clear')

2.6 Session—mysql

2.6.1 資料庫資訊配置

專案settings檔案的DATABASES中配置mysql引擎。

DATABASES = { 'default': { 'ENGINE' : 'django.db.backends.mysql', 'HOST': 'localhost',
                          #一般都是localhost 
                          'PORT': '3306',
                          #本地mysql服務執行的埠號 
                          'NAME': 'django3',
                          #本地mysql庫中存在設定的庫 
                          'USER': 'root',
                          #使用者必須為root 
                          'PASSWORD': '12345',
                          #cmd下連線mysql資料庫使用的密碼 } } 

2.6.2 執行遷移,生成Session表

在終端Terminal 專案目錄下執行資料表更新命令:

python manag.py makemigrations # 生成遷移檔案
python manag.py migrate  # 執行遷移

重新整理資料庫,檢視是否生成了django_session表

3 Session和Cookie的區別

  • cookie資料存放在客戶的瀏覽器上,session資料放在伺服器上。
  • cookie不是很安全,別人可以分析存放在本地的COOKIE並進行COOKIE欺騙 考慮到安全應當使用session。
  • session會在一定時間內儲存在伺服器上。當訪問增多,會比較佔用你伺服器的效能 考慮到減輕伺服器效能方面,應當使用COOKIE。
  • 單個cookie儲存的資料不能超過4K,很多瀏覽器都限制一個站點最多儲存20個cookie。
  • 所以個人建議: 將登陸資訊等重要資訊存放為SESSION 其他資訊如果需要保留,可以放在COOKIE中

4 Redis資料庫

4.1 Redis概述

  • 非關係型資料庫
  • 資料讀寫的速度快
  • 可以儲存的資料量少
  • 記憶體資料庫,支援資料的持久化,可以將記憶體中的資料儲存在磁碟中,重啟的時候可以再次載入進行使用。
  • Redis不僅僅支援簡單的key-value型別的資料,同時還提供list,set,zset,hash等資料結構的儲存。

4.2 Redis安裝

  • 下載課件,找到redis—msi的安裝包,也可在QQ群中下載。
  • 點選安裝包,一路next,finish完成安裝。
  • cmd下 輸入 redis –cli ,若出現以截圖,說明沒有把redis的資料庫新增到環境變數中

在這裡插入圖片描述

  • 得到以下截圖結果,說明安裝成功

png)]

4.3 Redis視覺化工具的使用

1.接下來我們來安裝Redis視覺化管理工具Redis Desktop Manager

2.安裝包在課件,qq群內均可下載。

3.安裝參考連結:https://jingyan.baidu.com/article/925f8cb8b92debc0dde05603.html

4.4 環境搭建(模組包的安裝)

pip install redis
pip install django-redis
pip install django-redis-sessions

注:若環境中存在2個Python版本,可使用pip3 進行安裝,mac使用者也可使用brew安裝

4.5 Session—Redis的使用

在settings中配置如下資訊:

SESSION_ENGINE = 'redis_sessions.session' \# 選擇Redis儲存Session
SESSION_REDIS_HOST = 'localhost' \# Redis的主機地址
SESSION_REDIS_PORT = 6379 \# Redis的埠號
SESSION_REDIS_DB = 0 \# 資料庫編號,0-11 SESSION_REDIS_PASSWORD = '' \#
登入Redis的密碼

注:完成配置,執行遷移,專案操作的session資訊會通過使用的redis-session引擎將資訊寫入到Redis資料庫中。

5 表單接收與提交

5.1 表單格式

5.1.1 基礎格式

form標籤 提交地址 action 提交方法 method get post 提交檔案 enctype="multipart/form-data" 
例如: 
<form action="www.edu.csdn.net" method="post" enctype="multipart/form-data > 

5.1.2 input屬性

屬性 說明
text 文字輸入框
password 密碼輸入框
radio 單選框
checkbox 核取方塊
file 檔案框
button 按鈕
submit 提交
reset 重置

5.1.3 下拉框

<select> 
    <option>選項1</option> 
    <option>選項2</option> 
</select>

5.1.4 大文字

<textarea cols="列數" rows="行數" > </textarea> 

5.1.5 表單程式碼例項

<!DOCTYPE html\> 
<html lang="en"> 
<head> 
    <meta charset="UTF-8"> 
    <title>Title</title> 
</head> 
<body> 
    <form action="{% url 'form_post' %}" > 
        username: <input type="text" name="username" ><br\> 
        hobby: <input type="checkbox" name="hobby" value="Python">Python 
        <input type="checkbox" name="hobby" value="Java">Java <br\>
        <input type="submit" value="submit"> 
    </form> 
</body> 
</html> 

5.2 請求原理

在這裡插入圖片描述

5.3 Get

5.3.1 提交

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="UTF-8"> 
    <title>Title</title> 
</head> 
<body> 
    <form action="{% url 'form_post' %}" method="get"> 
        username: <input type="text" name="username" ><br/> 
        hobby: <input type="checkbox" name="hobby" value="Python">Python 
        <input type="checkbox" name="hobby" value="Java">Java <br/> 
        <input type="submit" value="submit"> 
     </form> 
</body> 
</html>

5.3.2 接收

5.3.2.1 基礎格式

value = request.GET.get([key],[預設值]) values = request.GET.getlist ([key]) 

5.3.2.2 程式碼例項

1.url配置

path('form_get',views.form_get_handler,name='form_get'), 

2.views配置

def form_get_handler(request): 
    username = request.GET.get('username') 
    hobbys = request.GET.getlist('hobby') 
    print('username:',username) 
    print('hobbys',hobbys) 
    return HttpResponse('')

5.4 Post

5.4.1 提交

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="UTF-8"> 
    <title>Title</title> 
</head> 
<body> 
    <form action="{% url 'form_post' %}" method="post"> 
        {% csrf_token %} 
        username: <input type="text" name="username" ><br/> 
        hobby: <input type="checkbox" name="hobby" value="Python">Python 
        <input type="checkbox" name="hobby" value="Java">Java <br/> 
        <input type="submit" value="submit"> 
    </form> 
</body> 
</html> 

注:Post請求,需要在表單中加入{% csrf_token %},或者取消csrf中介軟體

5.4.2 接收

5.4.2.1 基礎格式

value = request.POST.get([key],[預設值]) values = request.POST.getlist ([key]) 

5.4.2.2 程式碼例項

1.url配置

path('form_post',views.form_post_handler,name='form_post'),

2.views配置

def form_post_handler(request): 
    username = request.POST.get('username') 
    hobbys = request.POST.getlist('hobby') 
    print('username:',username) 
    print('hobbys',hobbys) 
    return HttpResponse('') 

6 csrf跨域攻擊

6.1 原理

在這裡插入圖片描述

1.在django的任何post請求,都會在請求之初,給使用者下發一下串用來校驗身份的編碼,並且每次請求不一樣。

2.如果不加csrf_token校驗,會發生csrf錯誤

在這裡插入圖片描述

3.使用django的csrf校驗,{% csrf_token
%}標籤實際上就是在前端的form表單當中生成了一個hidden隱藏域,name為csrfmiddlewaretoken,value是csrf校驗的值

在這裡插入圖片描述

6.2 解決跨域攻擊

  1. 關閉中介軟體

在這裡插入圖片描述

  1. 表單加入{% csrf_token %}

在這裡插入圖片描述

6.3 程式碼例項

1.定義表單

在這裡插入圖片描述
2.url

在這裡插入圖片描述
3.檢視檔案, 完成註冊

在這裡插入圖片描述

7 模型類多表操作

7.1 基本原則

  • 一對一的表,兩表的屬性實際上完全可以合併成一個表,共用一個主鍵即可;
  • 一對多的表,可以設中間關聯表,也可以將關聯表併入“多”這頭;若設獨立關聯表,則可引入“多”這頭的主鍵作為其主鍵,也可另立主鍵並將“一”和“多”兩表的主鍵作為關聯表的外來鍵;
  • 多對多的表,則必須通過Django建立管理中間關聯表,關聯表設獨立主鍵,並引入兩個“多”頭的表的主鍵作為關聯表的外來鍵。
  • 能用1對1的,就不用1對多;能用1對多的,就不用多對多,往簡單化方向靠;
  • 能當屬性處理的,儘量當屬性,而不是當實體處理去另立新表,這樣可使問題簡化。
  • 把意義相近聯絡緊密的屬性放在一張表內,而不是拆在多張表中。

7.2 外來鍵種類

關鍵字 說明
ForeignKey 一對多 定義在多的一端中
ManyToManyField 多對多 定義在任意一方
OneToOneField 一對一 定義在任意一方

7.3 外來鍵常用引數

關鍵字 說明
to 引用的模型類
on_delete 外來鍵約束 on_delete=models.CASCADE 級聯操作(多對一,一的一方刪除,多的一方也刪除) on_delete=models.PROTECT 報異常(被引用的一方不能刪除) on_delete=models.SET_NULL 設定為null(多對一,一的一方刪除,多的一方外來鍵為null) on_delete=models.DO_NOTHING 什麼也不做
related_name 反向引用,如果兩個表間有多種外來鍵關係,需要指明related_name

7.4 一對一

7.4.1 概念

  • 子表從母表中選出一條資料一一對應,母表中選出來一條就少一條,子表不可以再選擇母表中已被選擇的那條資料
  • 一般用於某張表的補充,比如使用者基本資訊是一張表,但並非每一個使用者都需要有登入的許可權,不需要記錄使用者名稱和密碼,此時,合理的做法就是新建一張記錄登入資訊的表,與使用者資訊進行一對一的關聯,可以方便的從子表查詢母表資訊或反向查詢
  • 當某個物件想擴充套件自另一個物件,那可以再這個物件的主鍵上新增一對一的關係
  • 當某個物件想擴充套件自另一個物件,那可以再這個物件的主鍵上新增一對一的關係

7.4.2 程式碼例項

7.4.2.1 模型層的建立

# 通過 OneToOneField 建立一對一的關係 
from django.db import models 
class StaffInfo(models.Model):
    name = models.CharField(max_length=32, null=True) 
    age = models.CharField(max_length=32, null=True) 
class Salary(models.Model): 
    money = models.CharField(max_length=32, null=True) 
    staff = models.OneToOneField("StaffInfo")

7.4.2.2 增刪改查

# 增 和普通一樣

models.StaffInfo.objects.create(name="xxx",age=12)models.Salary.objects.create(money=3000, staff_id=2)

#一對一關聯的外來鍵如果新增重複會報錯,也就是說django已經幫我們做好了唯一索引
# 刪 和普通的也是一樣的

models.Salary.objects.filter(staff_id=2).delete()
#也有級聯刪除的問題, 可以通過on_delete 修改值取消級聯刪除改 和普通也一樣
models.Salary.objects.filter(staff_id=2).update(money=2000)

# 查分為正查和反差兩種
# 正查 通過點表中外來鍵名跨表查詢 row.staff.nameres = models.Salary.objects.all()
for row in res:
	print(row.money, row.staff.name)
# 反差點關聯表的表明小寫進行跨表查詢 row.salary.money
res = models.StaffInfo.objects.all()
for row in res:
	print(row.name, row.salary.money)

7.5 一對多

7.5.1 概念

  • 通過外來鍵來進行2張表的關聯操作
  • 子表從母表中選出一條資料一一對應,但母表的這條資料還可以被其他子表資料選擇

7.5.2 程式碼例項

7.5.2.1 模型層的建立

from django.db import models 
class User1(models.Model): 
    name = models.CharField(max_length=16,unique=True) 
	# 使用者名稱 
class Forum1(models.Model): 
    name = models.CharField(max_length=16,unique=True) 
    # 帖子主題 
    # 發帖的使用者 
    userObject = models.ForeignKey( to=User1, on_delete=models.CASCADE) 
    # ‘一’的一方的類 
    # 級聯操作 

7.5.2.2 新增與查詢

# 新增使用者 
user = User1.objects.create(name='name1') 
# 新增帖子,引用上面建立的使用者 
Forum1.objects.create(name='topic1',userObject=user) 
# 得到使用者發的所有帖子 \# 一對多,【多的一方的class名小寫_set】 
forum_s = User1.objects.get(id=1).forum1_set.all() print(forum_s)
# 得到帖子傳送者物件 
# 多對一,【通過定義的外來鍵欄位引用】 
user = Forum1.objects.get(name='topic1').userObject print(user) 
'''【結果】 
<QuerySet [<Forum1: Forum1 object>]> > User1 object 
''' 

7.5.2.3 引用關係

在這裡插入圖片描述

注:

M —>表示1對多

M得到引用的:通過M中定義的外來鍵欄位得到
得到被應用的所有M:通過M方的類名_set,返回時QuerySet物件,例如user1.forum1_set.all()

7.5.2.4 多對一的自關聯

使用to = ‘self’ 實現自關聯,推薦使用django來維護一對多的自關聯模型

  1. model.py
class Area(models.Model): 
    name = models.CharField(max_length=16,unique=True) 
    # 地區名字 
    pArea = models.ForeignKey(to='self',null=True) 
    # 上一級地區的引用 
    def __str__(self): 
        return str(self.name) 

  1. 測試
# area1:北京 
area1 = Area.objects.create(name='北京') 
# area2:朝陽 
area2 = Area(name='朝陽') 
# 設定area2的父地區是area1北京 
area2.pArea = area1 area2.save() 
# area3:豐臺 
area3 = Area.objects.create(name='豐臺') 
# area1北京的子地區,新增area3豐臺 
area1.area_set.add(area3) 
area_beijing = Area.objects.get(name='北京') 
area_chaoyang = Area.objects.get(name='朝陽') 
area_fengtai = Area.objects.get(name='豐臺') 
# 列印北京的所有子區域 
print(area_beijing.area_set.all()) 
# 列印朝陽的父區域 
print(area_chaoyang.pArea) 
'''
【結果】
<QuerySet [<Area: 朝陽>, <Area: 豐臺>]>  北京
'''

7.6 多對多

7.6.1 概念

  • 建立.多對多模型關係,Django會自己建立,維護一箇中間表。
  • django會自動建立一箇中間表:名稱:【app名】【類名小寫】【類名小寫】
  • 新增引用關係方法:add()
  • 刪除引用關係方法:remove()

7.6.2 測試

7.6.2.1 模型層的建立

class User2(models.Model): 
    name = models.CharField(max_length=16,unique=True) 
    # 使用者名稱 
    def __str__(self): 
        return str(self.name) 
class Hobby2(models.Model): 
    name = models.CharField(max_length=16,unique=True) 
    # 愛好名稱 
    userobjects = models.ManyToManyField(to=User2) 
    # 多對多 
    def __str__(self): 
        return str(self.name) 

7.6.2.2 增刪改查

user1 = User2.objects.create(name='name1') 
user2 = User2.objects.create(name='name2') 
# 建立3個愛好物件 
hobby1 = Hobby2.objects.create(name='早上寫程式碼') 
hobby2 = Hobby2.objects.create(name='中午寫程式碼') 
hobby3 = Hobby2.objects.create(name='晚上寫程式碼') 
# 通過使用者,新增引用 
user1.hobby2_set.add(hobby1) 
user1.hobby2_set.add(hobby2) 
# 通過愛好,新增引用 
hobby3.userobjects.add(user1) 
hobby3.userobjects.add(user2) 
print(user1.hobby2_set.all()) 
print(hobby3.userobjects.all()) 
# hobby3刪除引用的user1 
hobby3.userobjects.remove(user1) 
print(hobby3.userobjects.all()) 
'''【結果】 [<Hobby2: 中午寫程式碼>, <Hobby2: 早上寫程式碼>, <Hobby2: 晚上寫程式碼>] <QuerySet [<User2: name1>, <User2: name2>]> <QuerySet [<User2: name2>]> 
'''

print(row.money, row.staff.name)
# 反差 點關聯表的表明小寫進行跨表查詢 row.salary.money
res = models.StaffInfo.objects.all()
for row in res:
	print(row.name, row.salary.money)

7.6.3 through維護中間表

through指明中間表的模型類,如果自己指明瞭中間表,那麼django就不會幫助維護了,所有的新增刪除引用關係,都必須自己手動完成。

  1. model.py
class User3(models.Model): 
    name = models.CharField(max_length=16, unique=True) 
    # 使用者名稱 
    def __str__(self): 
        return str(self.name) 
class Hobby3(models.Model): 
    name = models.CharField(max_length=16, unique=True) 
    # 愛好名稱
    userobjects = models.ManyToManyField(to=User3,through='User3ToHobby3') 
    # 多對多 
    def \__str__(self): 
        return str(self.name) 
class User3ToHobby3(models.Model): 
    user = models.ForeignKey(to=User3) 
    hobby = models.ForeignKey(to=Hobby3)

  1. 測試
# 建立使用者物件 
user1 = User3.objects.create(name='name1') 
user2 = User3.objects.create(name='name2') 
# 建立愛好物件 
hobby1 = Hobby3.objects.create(name='早上寫程式碼') 
hobby2 = Hobby3.objects.create(name='中午寫程式碼') 
hobby3 = Hobby3.objects.create(name='晚上寫程式碼') 
# 自己手動維護中間表 
User3ToHobby3.objects.create(user=user1,hobby=hobby1) User3ToHobby3.objects.create(user=user1,hobby=hobby2) User3ToHobby3.objects.create(user=user2,hobby=hobby2) User3ToHobby3.objects.create(user=user2,hobby=hobby3) 
print(user1.hobby3_set.all()) 
print(hobby3.userobjects.all()) 
'''【結果】 >> <QuerySet [<Hobby3: 早上寫程式碼>, <Hobby3: 中午寫程式碼>]
		  >> <QuerySet [\<User3: name2\>]\> 
'''

7.7 一對多 多對多 一對一的詳細例項

參考以下連結: https://blog.csdn.net/jiangbo721/article/details/89918381

8 中介軟體Middleware應用

8.1 概念

中介軟體是一個輕量級、底層的外掛系統,可以介入Django的請求和響應處理過程,修改Django的輸入或輸出

8.2 原理

在http請求 到達檢視函式之前 和檢視函式return之後,django會根據自己的規則在合適的時機執行中介軟體中相應的方法。Django1.9版本以後中介軟體的執行流程

  • 執行完所有的request方法 到達檢視函式。
  • 執行中介軟體的其他方法
  • 經過所有response方法 返回客戶端。

注意:如果在其中1箇中介軟體裡 request方法裡return了值,就會執行當前中介軟體的response方法,返回給使用者 然後報錯。。不會再執行下一個中介軟體。

在這裡插入圖片描述

在這裡插入圖片描述

8.3 中介軟體的註冊

settings.py檔案內設定MIDDLEWARE的值。

在這裡插入圖片描述

8.4 方法詳解

8.4.1 init

沒有引數,伺服器響應第一個請求的時候自動呼叫,使用者確定是否啟用該中介軟體

8.4.2 process_request(self,request) 常用

  • 在執行檢視前被呼叫,每個請求上都會呼叫
  • 不返回或返回HttpResponse物件
  • 沒有return或者return None 繼續呼叫其他檢視
  • return response 則不會呼叫其他檢視

8.4.3 process_view(self,request,view_func,view_args,view_kwargs)

呼叫檢視之前執行,每個請求都會呼叫2.不返回或返回HttpResponse物件

8.4.4 process_template_response(self,request,response)

在檢視剛好執行完後進行呼叫,每個請求都會呼叫2.不返回或返回HttpResponse物件

8.4.5 process_response(self,request,response)

所有響應返回瀏覽器之前呼叫,每個請求都會呼叫2.不返回或返回HttpResponse物件3.必須return response

8.4.6 process_exception(self,request,exception)

  • 當檢視丟擲異常時呼叫
  • 不返回或返回HttpResponse物件

8.5 使用場景

由於中介軟體工作在
檢視函式執行前、執行後(像不像所有檢視函式的裝飾器!)適合所有的請求/一部分請求做批量處理

  • 做IP限制
    • 放在 中介軟體類的列表中,阻止某些IP訪問了;
  • URL訪問過濾
    • 如果使用者訪問的是login檢視(放過)如果訪問其他檢視(需要檢測是不是有session已經有了放行,沒有返回login),這樣就省得在多個檢視函式上寫裝飾器了!
    • 快取(還記得CDN嗎?)
  • 客戶端請求來了,中介軟體去快取看看有沒有資料,有直接返回給使用者,沒有再去邏輯層
    執行檢視函

9 admin後臺管理

9.1 概念

  • django amdin是django提供的一個後臺管理頁面,改管理頁面提供完善的html和css,使得你在通過Model建立完資料庫表之後,就可以對資料進行增刪改查
  • 管理介面不是讓訪問網站的人使用的,它服務於網站管理者。 它用於網站的管理員。

9.2 建立管理員使用者

  • 開啟treminal 輸入 python manage.py createsuperuser 然後回車
  • 自定義使用者名稱,密碼,郵箱號

在這裡插入圖片描述

注: 輸入密碼是 密碼是不可見的,輸入時需要注意,.

9.3 admin登入

  • 開啟主路由自帶的admin路由

在這裡插入圖片描述

  • 啟動服務,在前臺輸入url127.0.0.1/埠號/admin
  • 輸入剛才自定義的賬號密碼進行登入

9.4 admin管理後臺

9.4.1 admin.py

9.4.1.1 引數詳解

引數 說明
@admin.register(模型類) 在後臺註冊匯入的模型類
list_display 定義展示的欄位
search_fields 定義支援模糊查詢的欄位
filter_horizontal 定義多表顯示
list_filter 定義右側的過濾器
admin.site.site_header 設定網站頁頭
admin.site.site_title 設定頁面標題
admin.site.index_title 設定首頁標語

9.4.1.2 程式碼例項

在這裡插入圖片描述

在這裡插入圖片描述

9.4.2 app.py

9.4.2.1 引數詳解

引數 說明
verbose_name 定義app顯示的名字

9.4.2.2 程式碼例項

在這裡插入圖片描述

9.4.3 model.py

9.4.3.1 引數詳解

引數 說明
Blank 預設為Fasle 新增欄位時不允許為空
Choices 下拉選框和模型類欄位的繫結, Django中推薦CHOICES大寫
related_name 自定義表的外來鍵,用於模型類的反向查詢
upload_to 定義上傳檔案的儲存方法

9.4.3.2 程式碼例項

在這裡插入圖片描述

在這裡插入圖片描述

10 專案淺析

10.1 專案結構

10.1.1 static

存放專案中使用的 css,js,img,video檔案

10.1.2 templete

存放專案中使用的前端html檔案。

10.1.3 user

1.定義使用者的模型類。

2.指定後臺管理顯示的內容。

3.使用者的註冊,登入,退出 。

4.購物車的 顯示,增加,購買。

10.1.4 course

1.定義課程的模型類,圖片和視訊的儲存方式。

2.指定後臺管理顯示的內容。

3.前臺主頁課程的顯示。

4.課程詳情頁的載入。

5.視訊的播放

10.1.5 middleware

1.全域性context的定義

2.前臺登入後使用者的顯示。

3.使用者的登陸判斷,若沒登入則跳轉登入頁面

10.1.6 settings

10.1.6.1 INSTALLED_APPS

應用的載入

在這裡插入圖片描述

10.1.6.2 MIDDLEWAER

新增自定義的中介軟體檔案

在這裡插入圖片描述

10.1.6.3 TEMPLATES

在這裡插入圖片描述

10.1.6.4 DATABASES

在這裡插入圖片描述

注:資料庫和密碼換成自己本地使用的資料庫和密碼

10.1.6.5 語言和時區

在這裡插入圖片描述

10.1.6.6 static靜態檔案

在這裡插入圖片描述

10.2 專案執行

10.2.1 資料庫遷移

在這裡插入圖片描述

在這裡插入圖片描述

10.2.2 後臺管理員的建立

在這裡插入圖片描述

10.2.3 後臺資料的新增

1.啟動服務

在這裡插入圖片描述

2.訪問專案

在這裡插入圖片描述

在這裡插入圖片描述

在這裡插入圖片描述

注:訪問http://127.0.0.1:8000/admin 路由進行後臺使用者的登入.

在這裡插入圖片描述

4a83c85fd0961f7fbe63b83dca095944.png

注:新增使用者,課程種類,課程表.

在這裡插入圖片描述

10.3 功能解析

10.3.1主頁課程的展示

在這裡插入圖片描述

10.3.2 主頁登入,登出和使用者資訊顯示

在這裡插入圖片描述

在這裡插入圖片描述

10.3.3 課程詳情頁的展示.

在這裡插入圖片描述

在這裡插入圖片描述

10.3.4 購物車操作:加入,購買

在這裡插入圖片描述

在這裡插入圖片描述

在這裡插入圖片描述
注:user_shoppingcart.html中url快捷呼叫user_purcharse,攜帶課程id,完成購買。

10.3.4 課程觀看

在這裡插入圖片描述

相關文章