1. 程式人生 > 其它 >web框架推導 wsgiref模組 jinja2模板語法 django框架簡介 django基本操作

web框架推導 wsgiref模組 jinja2模板語法 django框架簡介 django基本操作

目錄

純手擼web框架

web框架的本質

瀏覽器 --- web框架 --- 資料庫
理解1:web框架連線前端與資料庫的中間介質

瀏覽器(客戶端)---> web框架(服務端)
理解2:web框架是一個socket服務端
web框架就是一個服務端!
提供頁面,從資料庫中拿資料。

手寫web框架

  1. 編寫socket服務端程式碼

  2. 瀏覽器訪問響應無效>>>:HTTP協議

    為什麼顯示響應無效?
    瀏覽器不認識服務端的響應 我們的服務端接受到瀏覽器的請求之後 返回一個字串 瀏覽器不認識這種格式
    瀏覽器只支援http協議的資料格式(響應頭 響應體)所以需要給字串包裝一下 加個響應頭
    sock.send(b'HTTP/1.1 200 OK\r\n\r\n')

  3. 根據網址字尾的不同獲取不同的頁面內容
    輸入網址:127.0.0.1:8080/login 跳轉到登入頁面
    輸入網站:127.0.0.1:8080/rigister跳轉到註冊頁面

  4. 想辦法獲取到使用者輸入的字尾>>>:請求資料
    要實現這個功能我們需要研究下瀏覽器傳送的請求資訊是什麼?

    發現請求首行這個固定的位置,就有我們想要的資訊(/login)。這個請求資訊,經過解碼就變成了一個字串,我們可以使用正則或者split方法,將其匹配。

更多請求時的例子:

第一個是瀏覽器向127.0.0.1:8080/傳送請求,第二個無需在意。

  1. 請求首行
    瀏覽器傳送的請求也是有區別的:先介紹兩種 GET、POST
    (請求首行:GET /login HTTP/1.1)
    5.1 GET請求
    朝別人索要資料 你把你的首頁給我!向伺服器索要html頁面
    5.2 POST請求
    朝別人提交資料 註冊登入時 將使用者名稱密碼交給服務端

  2. 處理請求資料獲取網址字尾
    這時候我們就可以根據不同的請求資料 給瀏覽器發不同的訊息了,寫if分支結構:

    我們上面傳送的是字串,也可以傳送html檔案:

    rb模式讀取html,以二進位制格式(bytes)傳送給瀏覽器。這樣就完成了一個簡單的web伺服器。

程式碼如下:

import socket


server = socket.socket()  # TCP UDP
server.bind(('127.0.0.1', 8080))  # IP PORT
server.listen(5)  # 半連線池


while True:
    sock, address = server.accept()  # 等待連線
    data = sock.recv(1024)  # 位元組(bytes)
    # print(data.decode('utf8'))  # 解碼列印
    sock.send(b'HTTP/1.1 200 OK\r\n\r\n')
    data_str = data.decode('utf8')  # 先轉換成字串
    target_url = data_str.split(' ')[1]  # 按照空格切割字串並取索引1對應的資料
    # print(target_url)  # /index /login /reg
    if target_url == '/index':
        # sock.send(b'index page')
        with open(r'myhtml01.html','rb') as f:
            sock.send(f.read())
    elif target_url == '/login':
        sock.send(b'login page')
    else:
        sock.send(b'home page!')

存在的問題

  1. socket程式碼過於重複
  2. 針對請求資料處理繁瑣
    請求資料 我們只拿了一個數據 如果想拿更多的東西?那不是對請求 需要做更多的處理?
  3. 字尾匹配邏輯過於LowB
    字尾多的時候 :寫100個if elif 字尾匹配邏輯太low

基於wsgiref模組

基本介紹

內建模組 很多web框架底層使用的模組
功能1:封裝了socket程式碼
功能2:處理了請求、響應資料
(給字串新增 響應頭 給接收到的請求資訊 自動處理成字典方便呼叫)

推導流程

1.固定程式碼啟動服務端

看這行:
make_server(127.0.0.1, 8080, run)
一旦有瀏覽器向我們的伺服器傳送請求,自動觸發run函式,自動給第三個引數run函式加括號呼叫並傳引數,給run傳的這個引數就是處理好的請求資訊(大字典)
補充:我們make_server這裡放的是run函式,能不能放一個物件?因為make_server可以自動加呼叫嘛。
這時候就要複習下了:
函式名加括號 ---> 函式執行
類名加括號 ---> 產生物件
物件加括號 ---> ???
物件加括號:理論上直接報錯 但是如果你定義了雙下__call__會自動觸發!好就到這裡,繼續之前的思路。
還需要新增一行程式碼,我們的服務端才能起來:
server.serve_forever()

伺服器等待請求中:

每次請求都是觸發run函式,無論你用什麼字尾:

2.檢視處理之後的request大字典>>>:研究大字典鍵值對
裡面path_info是我們要的網址字尾:

3.根據不同的網址字尾返回不同的內容
從request字典裡面取值,寫if邏輯判斷:
針對/index頁面返回字串'index',在經過wsgiref模組自動加響應頭,傳送給瀏覽器。

4.立刻解決上述純手擼的兩個問題
socket程式碼過於重複 --> wsgirel模組幫你寫
針對請求資料處理繁瑣 --> wsgirel模組幫你打包成字典
5.針對最後一個問題程式碼如何優化
字尾匹配邏輯(if分支結構冗餘)

程式碼:

from wsgiref.simple_server import make_server
def run(request, response):
    """
    :param request: 請求相關資料
    :param response: 響應相關資料
    :return: 返回給客戶端的真實資料
    """
    response('200 OK', [])  # 固定格式 不用管它
    # print(request)  是一個處理之後的大字典
    path_info = request.get('PATH_INFO')
    if path_info == '/index':
        return [b'index']
    elif path_info == '/login':
        return [b'login']
    return [b'hello wsgiref module']


if __name__ == '__main__':
    server = make_server('127.0.0.1', 8080, run)  # 實時監聽127.0.0.1:8080 一旦有請求過來自動給第三個引數加括號並傳引數呼叫
    server.serve_forever()  # 啟動服務端

程式碼封裝優化

1.網址字尾的匹配問題分析

問題1:if elif 隨著頁面增多而增多 有100個頁面就要寫100個if
問題2:每個字尾匹配成功後執行程式碼有多有少 萬一有10000行程式碼怎麼辦,都放在一個if分支下面嗎? 問題2很重要,慢慢拆分來解決!!

2.每個字尾匹配成功後執行的程式碼有多有少
我們現在相當於麵條版,需要慢慢升級!
麵條版 ---> 函式版 ---> 模組版
3.將分支的程式碼封裝成一個個函式
將每個頁面拆分成一個個函式:

4.將網址字尾與函式名做對應關係
url列表套元祖(解決if判斷):

5.獲取網址字尾迴圈匹配

一旦匹配成功應該結束for迴圈:

可能匹配結束之後,匹配不到,此時funcname=NONE
所以要加一個funcname的判斷:

最終還是要看下面這個return:
6.如果想新增功能只需要先寫函式再新增一個對應關係即可
res都是字串!

這樣寫就相當於可以新增字尾 新增功能
核心是:獲取網址字尾for迴圈匹配

還不夠完美!這些功能函式全寫在一起了!要根據功能不同進行拆分!

7.根據不同的功能拆分成不同的py檔案
views.py 儲存核心業務邏輯(功能函式)
urls.py 儲存網址字尾與函式名對應關係
templates目錄 儲存html頁面檔案
run函式匯入urls.py:

urls.py帶入views:

請求:RUN函式 ---> url選擇器 ---> views
響應:RUN return <----views return

8.為了使函式體程式碼中業務邏輯有更多的資料可用
將request大字典轉手傳給這個函式(可用不用但是不能沒有)

ps: funcname的res返回值是包含html資訊的字串 經過編碼就可以傳送給瀏覽器

總結

核心思路就是解決三個問題:

1socket程式碼總是要寫!
2.請求資料拿不全 我們只拿了一個數據 如果想拿更多的東西?那不是對請求 需要做更多的處理?
3.字尾多的時候 :寫100個if elif 字尾匹配邏輯太low

動靜態網頁

動態網頁
頁面資料來源於後端
靜態網頁
頁面資料直接寫死

簡單實現動態網頁:
訪問某個網址字尾 後端程式碼獲取當前時間 並將該時間傳到html檔案上再返回給瀏覽器展示給使用者看

  1. 將時間資訊塞到html頁面中?怎麼塞??

    open方法r模式開啟html 用變數data接受 data是個字串!
    所以我們可以:
    讀取html內容(字串型別) 然後利用字串替換(replace) 最後再返回給瀏覽器
  2. 先在html打個標記(類似佔位符):
  3. 對標記做替換:

jinja2模組實現動態網頁:
需求:將字典傳遞給頁面內容 並且在頁面上還可以通過類似於後端的操作方式操作該資料(就是在前端可以寫python語法 使用for迴圈 if判斷等)

jinja2模組

這是一個第三方模組。
他可以讓你在html上面寫python程式碼。
原理:所謂的模板語法 還是隻有後端才認識 瀏覽器不認識(瀏覽器只支援html\css\js) jinja2模組可以自動解析html頁面的模板語法 新增資料 生成新的html頁面 然後再交給前端執行
匯入:

寫模板語法:

render函式的第一個引數是在模板語法中使用的變數名,第二個引數是這個變數名對應的資料值。

pip3 install jinja2


from jinja2 import Template


def get_dict_func(request):
    user_dict = {'name': 'jason', 'age': 18, 'person_list': ['阿珍', '阿強', '阿香', '阿紅']}
    with open(r'templates/get_dict_page.html', 'r', encoding='utf8') as f:
        data = f.read()
    temp_obj = Template(data)  # 將頁面資料交給模板處理
    res = temp_obj.render({'d1': user_dict})  # 給頁面傳了一個 變數名是d1值是字典資料的資料
    return res

<p>{{ d1 }}</p>
<p>{{ d1.name }}</p>
<p>{{ d1['age'] }}</p>
<p>{{ d1.get('person_list') }}</p>

前端、後端、資料庫三者聯動

簡單的說,就是在功能函式中使用pymysql模組。
然後將得到的資料,通過模板語法,動態新增到html頁面上。模板語法對html頁面做一些操作,產生新的html頁面,這個過程稱為‘渲染’。

推導流程

新增url選擇器 新增函式 寫函式 新增pymysql:

我們還要將資料表的樣式搞下 用cdn 暫時別用本地,現在還不會用,可能會出問題:

將資料庫的資料傳給模板(Template類產生的物件):

編寫html,以及模板語法:

使用for迴圈,書寫表單體:

總結

python主流web框架

"""
作為小白的你 初學階段不要混著學 很容易走火入魔
"""
1.django
	大而全 自身自帶的功能元件非常的多 類似於航空母艦 		
2.flask
	小而精 自身自帶的功能元件非常的少 類似於遊騎兵
 	幾乎所有的功能都需要依賴於第三方模組 
3.tornado
	非同步非阻塞 速度極快效率極高甚至可以充當遊戲服務端
	封裝多程序多執行緒 可選同步非同步
ps:sanic、fastapi...

django簡介

版本問題

    django1.X:同步		1.11
    django2.X:同步		2.2
    django3.X:支援非同步    3.2
    django4.X:支援非同步	   4.2
ps:版本之間的差異其實不大 主要是添加了額外的功能

執行django注意事項

1.django專案中所有的檔名目錄名不要出現中文
2.計算機名稱儘量也不要出現中文
3.一個pycharm儘量就是一個完整的專案(不要巢狀 不要疊加)
4.不同版本的python直譯器與不同版本的django可能會出現小問題


計算機名不能為中文:會報編碼錯誤

django基本使用

1. 下載

pip3 install django 			預設最新版
pip3 install django==版本號		  指定版本
pip3 install django==2.2.22
pip下載模組會自動解決依賴問題(會把關聯需要用到的模組一起下了)

2. 驗證

django-admin
django下好了 會自動在python/scrpit目錄下新增django-admin.exe 
如果輸入django-admin終端顯示找不到檔案 
先檢查環境變數是否新增scrpit目錄 再去該目錄下檢視exe檔案是否存在 
如果exe不存在,則考慮重灌django。

3. 常見命令

1.建立django專案
	django-admin startproject 專案名
2.啟動django專案
	cd 專案名
	python38 manage.py runserver ip:port
	manage檔案相當於上面寫的run函式那個檔案。
	預設會在8000段口起了一個服務

4. pycharm自動建立django專案

會自動建立templates資料夾 但是配置檔案中可能會報錯
	os.path.join(BASE_DIR,'templates')

如下是pycharm建立的settings:

修改一下(路徑分隔符錯誤):

注意應該改成這樣:[os.path.join(BASE_DIR,'templates'),]
用pycharm提供的專案啟動:

可以改埠:

不小心把啟動檔案刪掉了:
自己新增django server

django app的概念

django類似於是一所大學 app類似於大學裡面的各個學院

django裡面的app類似於某個具體的功能模組
	user	app 所有使用者相關的都寫在user app下
 	goods	app 所有商品相關的都寫在goods app下
 
命令列建立應用
	python38 manage.py startapp 應用名
pycharm建立應用
	新建django專案可以預設建立一個 並且自動註冊
"""
建立的app一定要去settings.py中註冊
	INSTALLED_APPS = [
    	'app01.apps.App01Config',
		'app02'
	]
"""

pycharm自動建立app

pycharm建立django專案的時候自動幫你創一個app:

好處:app需要在settings註冊 (給校長打招呼)
pycharm建立的應用會自動註冊一下

建立的app一定要去settings註冊,不然django不帶你玩。
註冊時有兩種寫法:完整和簡寫

pycharm提供一個manage.py終端:

django主要目錄結構

django專案目錄名>>>

	django專案同名目錄>>>
    	settings.py		配置檔案
    	urls.py			儲存網址字尾與函式名對應關係(不嚴謹)
   	wsgi.py			wsgiref閘道器檔案
	db.sqlite3檔案		django自帶的小型資料庫(專案啟動之後才會出現)
	manage.py		入口檔案(命令提供)
	
 	app應用目錄>>>
    	migrations目錄		儲存資料庫相關記錄
    	admin.py		django內建的admin後臺管理功能
        apps.py			註冊app相關
   	models.py		與資料庫打交道的(非常重要)
    	tests.py		測試檔案
    	views.py		儲存功能函式(不嚴謹)
		
   	templates目錄>>>
	儲存html檔案(命令列不會自動建立 pycharm會)
	
    	配置檔案settings中還需要配置路徑
        	[os.path.join(BASE_DIR,'templates'),]
 
"""
重要名詞講解
	網址字尾				路由
	函式				檢視函式
	類				檢視類

	urls.py				路由層	
	views.py			檢視層
	models.py			模型層
	templates			模板層
"""

小江狗(django)必會三板斧(需要補充)

from django.shortcuts import render,HttpResponse,redirect

HttpResponse		 返回字串型別的資料

render				返回html頁面並且支援傳值

redirect			重定向