web框架推導 wsgiref模組 jinja2模板語法 django框架簡介 django基本操作
- 純手擼web框架
- 基於wsgiref模組
- 程式碼封裝優化
- 動靜態網頁
- jinja2模組
- 前端、後端、資料庫三者聯動
- python主流web框架
- django簡介
- django基本使用
- django app的概念
- django主要目錄結構
- 小江狗(django)必會三板斧(需要補充)
純手擼web框架
web框架的本質
瀏覽器 --- web框架 --- 資料庫
理解1:web框架連線前端與資料庫的中間介質
瀏覽器(客戶端)---> web框架(服務端)
理解2:web框架是一個socket服務端
web框架就是一個服務端!
提供頁面,從資料庫中拿資料。
手寫web框架
-
編寫socket服務端程式碼
-
瀏覽器訪問響應無效>>>:HTTP協議
為什麼顯示響應無效?
瀏覽器不認識服務端的響應 我們的服務端接受到瀏覽器的請求之後 返回一個字串 瀏覽器不認識這種格式
瀏覽器只支援http協議的資料格式(響應頭 響應體)所以需要給字串包裝一下 加個響應頭sock.send(b'HTTP/1.1 200 OK\r\n\r\n')
-
根據網址字尾的不同獲取不同的頁面內容
輸入網址:127.0.0.1:8080/login
跳轉到登入頁面
輸入網站:127.0.0.1:8080/rigister
跳轉到註冊頁面 -
想辦法獲取到使用者輸入的字尾>>>:請求資料
要實現這個功能我們需要研究下瀏覽器傳送的請求資訊是什麼?
發現請求首行這個固定的位置,就有我們想要的資訊(/login)。這個請求資訊,經過解碼就變成了一個字串,我們可以使用正則或者split方法,將其匹配。
更多請求時的例子:
第一個是瀏覽器向127.0.0.1:8080/
傳送請求,第二個無需在意。
-
請求首行
瀏覽器傳送的請求也是有區別的:先介紹兩種 GET、POST
(請求首行:GET /login HTTP/1.1)
5.1 GET請求
朝別人索要資料 你把你的首頁給我!向伺服器索要html頁面
5.2 POST請求
朝別人提交資料 註冊登入時 將使用者名稱密碼交給服務端 -
處理請求資料獲取網址字尾
這時候我們就可以根據不同的請求資料 給瀏覽器發不同的訊息了,寫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!')
存在的問題
- socket程式碼過於重複
- 針對請求資料處理繁瑣
請求資料 我們只拿了一個數據 如果想拿更多的東西?那不是對請求 需要做更多的處理? - 字尾匹配邏輯過於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檔案上再返回給瀏覽器展示給使用者看
- 將時間資訊塞到html頁面中?怎麼塞??
open方法r模式開啟html 用變數data接受 data是個字串!
所以我們可以:
讀取html內容(字串型別) 然後利用字串替換(replace) 最後再返回給瀏覽器 - 先在html打個標記(類似佔位符):
- 對標記做替換:
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 重定向