Web框架初識以及Django框架簡介
內容概要
- 原始web框架
- wsgiref 功能模組
- 主要檔案與程式碼封裝
- 動靜態網頁
- 模板語法簡介
- python三大主流web框架
- Django 簡介以及基本操作
- Django 必會三板斧
內容詳細
原始web框架
python 進行網路程式設計可以用 socket 模組
可以把web應用理解為一個 socket 服務端,而使用者瀏覽器是一個 socket 客戶端
自定義web框架:
import socket server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(('127.0.0.1', 8080)) server.listen(5) sock, addr = server.accept() data = sock.recv(10000) sock.send(b'HTTP/1.1 200') sock.close() server.close()
Web服務本質上都是在這十幾行程式碼基礎上擴展出來的
data 是瀏覽器傳送給後端的請求資料:
b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8080\r\nConnection: keep-alive\r\nPragma: no-cache\r\nCache-Control: no-cache\r\nsec-ch-ua: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"\r\nsec-ch-ua-mobile: ?0\r\nsec-ch-ua-platform: "Windows"\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\nSec-Fetch-Site: none\r\nSec-Fetch-Mode: navigate\r\nSec-Fetch-User: ?1\r\nSec-Fetch-Dest: document\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: _ga=GA1.4.755355248.1635858969; csrftoken=hP3rSmCtH1jKsiUhEC2ufs3p0q3F08TDvpNsftS78IEQqWvnAWWHO2FhnLtKfhMe; sessionid=cp7co0il32xqfcmdmu5dpxjdphe9oaj9\r\n\r\n'
在應用層上,瀏覽器與服務端資料互動遵循的是 HTTP 協議
請求資料:
服務端響應給瀏覽器的資料資訊:(需要點選view source)
在瀏覽器傳送的請求資料中,包括了請求首行中的請求方式,也包括了請求頭中的路由(資源地址)和協議名稱,服務端接收到請求資料之後需要對資料進行進一步分析,給瀏覽器響應回相應的網頁資源
下面,直接書寫純手擼web框架的最終版本:
""" 根據URL中不同的路徑返回不同的內容--函式進階版 返回HTML頁面 讓網頁動態起來 """ import socket import time sk = socket.socket() sk.bind(("127.0.0.1", 8080)) # 繫結IP和埠 sk.listen() # 監聽 # 將返回不同的內容部分封裝成函式 def index(url): with open("index.html", "r", encoding="utf8") as f: s = f.read() now = str(time.time()) s = s.replace("@@oo@@", now) # 在網頁中定義好特殊符號,用動態的資料去替換提前定義好的特殊符號 return bytes(s, encoding="utf8") def home(url): with open("home.html", "r", encoding="utf8") as f: s = f.read() return bytes(s, encoding="utf8") # 定義一個url和實際要執行的函式的對應關係 list1 = [ ("/index/", index), ("/home/", home), ] while 1: # 等待連線 conn, add = sk.accept() data = conn.recv(8096) # 接收客戶端發來的訊息 # 從data中取到路徑 data = str(data, encoding="utf8") # 把收到的位元組型別的資料轉換成字串 # 按\r\n分割 data1 = data.split("\r\n")[0] url = data1.split()[1] # url是我們從瀏覽器發過來的訊息中分離出的訪問路徑 conn.send(b'HTTP/1.1 200 OK\r\n\r\n') # 因為要遵循HTTP協議,所以回覆的訊息也要加狀態行 # 根據不同的路徑返回不同內容 func = None # 定義一個儲存將要執行的函式名的變數 for i in list1: if i[0] == url: func = i[1] break if func: response = func(url) else: response = b"404 not found!" # 返回具體的響應訊息 conn.send(response) conn.close()
在該版本的web框架中,web服務可以根據不同的路徑返回不同的內容,並且能直接以檔案操作的方式返回HTML頁面。
wsgiref 功能模組
WSGI(Web Server Gateway Interface)是一種協議,它定義了使用Python編寫的web應用程式與web伺服器程式之間的介面格式,實現web應用程式與web伺服器程式間的解耦
wsgiref 和 uwsgi 是實現這種協議的功能模組
wsgiref 是 Python標準庫提供的獨立WSGI伺服器,Django開發環境用的就是這個模組來做伺服器。
利用wsgiref模組來替換我們自己寫的web框架的socket server部分:
"""
根據URL中不同的路徑返回不同的內容--函式進階版
返回HTML頁面
讓網頁動態起來
wsgiref模組版
"""
import time
from wsgiref.simple_server import make_server
# 將返回不同的內容部分封裝成函式
def index(url):
with open("index.html", "r", encoding="utf8") as f:
s = f.read()
now = str(time.time())
s = s.replace("@@oo@@", now)
return bytes(s, encoding="utf8")
def home(url):
with open("home.html", "r", encoding="utf8") as f:
s = f.read()
return bytes(s, encoding="utf8")
# 定義一個url和實際要執行的函式的對應關係
list1 = [
("/index/", index),
("/home/", home),
]
def run_server(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # 設定HTTP響應的狀態碼和頭資訊
url = environ['PATH_INFO'] # 取到使用者輸入的url
func = None
for i in list1:
if i[0] == url:
func = i[1]
break
if func:
response = func(url)
else:
response = b"404 not found!"
return [response, ]
if __name__ == '__main__':
httpd = make_server('127.0.0.1', 8090, run_server)
print("我在8090等你哦...")
httpd.serve_forever()
主要檔案與程式碼封裝
上面封裝好的 web 框架程式碼,為了解耦合,增強他們的拓展性,可以根據不同功能存放到不同的檔案中
處理業務邏輯的程式碼放在 views.py 檔案中:
做路由分發的程式碼放在 urls.py 檔案中:
啟動服務端的程式碼放在啟動檔案中:
動靜態網頁
靜態網頁: 前端頁面上的資料全都是展示之前準備好的,固定不變的,資料不能進行實時更改
動態頁面: 前端頁面上的資料可以實時獲取並展示,可以從後端獲取資料,也可以從資料庫中查詢獲取到展示在頁面上
靜態網頁:
1、不含後臺收據庫,不可互動。靜態網頁內容相對固定,容易被搜尋引擎檢索,且不需要連線資料庫,因此響應速度較快。適合於做展示作品的網站。
2、靜態網頁並不是靜止不動的,它也可以出現各種動態的效果,如 GIF 動畫、FLASH、滾動字幕等。它的更新和維護也非常麻煩。
3、靜態網頁服務的實現首先需要客戶機通過瀏覽器向伺服器發出請求,然後伺服器接受請求並根據請求從伺服器端的網頁中找到對應的頁面,最後返回給客戶機瀏覽器。這個過程中所傳送的頁面都是事先編輯好的,它並不能自動生成。
動態網頁:
1、動態網頁是基本的 HTML 語法規範與 PHP、Java、Python 等程式語言、資料庫等多種技術的融合,可以理解為凡是結合了 HTML 以外的高階程式設計語言和資料庫技術進行的網頁程式設計技術生成的網頁都是動態網頁。動態網頁可以很好地實現和使用者的互動,可以實現更多的功能,如使用者的登入、註冊、查詢等。
2、動態網頁與網頁上的各種動畫、滾動字幕等視覺上的動態效果沒有直接關係,動態網頁也可以是純文字內容的,也可以包含各種動畫的內容,只要是採用了動態網站技術(如 PHP、JSP 等)生成的網頁都可以稱為動態網頁。
3、與靜態網頁的實現方法不同,動態網頁服務的實現首先需要客戶機向伺服器傳送請求,然後伺服器根據使用者請求把動態網頁內部的程式碼先在伺服器上進行相應的處理,最後伺服器把生成的結果傳送給客戶機
模板語法簡介
從後端獲取資料之後,在前端怎麼樣能方便快捷地對資料進行處理並展示出來呢?這裡就要使用到模板語法
在 python 中,可以使用模組 jinja2 實現前端頁面文件獲取後端資料的功能
# 下載
pip install jinja2
前端 HTML 檔案:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
</head>
<body>
<h1>姓名:{{name}}</h1>
<h1>愛好:</h1>
<ul>
{% for hobby in hobby_list %}
<li>{{hobby}}</li>
{% endfor %}
</ul>
</body>
</html>
# {{ }} 可以獲取後端的變數
# {% %} 可以在前端實現簡單的流程控制程式碼
後端給前端檔案傳送資料:
from wsgiref.simple_server import make_server
from jinja2 import Template
def index():
with open("index2.html", "r") as f:
data = f.read()
template = Template(data) # 生成模板檔案
ret = template.render({"name": "Alex", "hobby_list": ["燙頭", "泡吧"]}) # 把資料填充到模板裡面
return [bytes(ret, encoding="utf8"), ]
python三大主流web框架
1、優缺點對比
- Django
優點: 體量大、功能齊全,自帶功能特別特別多,類似航空母艦
**缺點: ** 有時過於笨重
- Flask
優點: 小而精,自帶功能少,但第三方模組特別多,加起來甚至可以超過Django,也越來越像Django
**缺點: ** 比較依賴第三方開發者
- tornado
優點: 非同步非阻塞,支援高併發,甚至可以用來開發遊戲伺服器
**缺點: **
2、功能對比
Django 請求生命週期流程圖
web服務閘道器介面
Django使用自帶的wsgiref模組
作用:
- 收到請求時,對http協議格式的請求資料進行解析,並封裝成字典格式;
- 傳送響應時,將響應資料封裝成符合http協議格式的資料。
補充:
wsgiref模組支援的併發量不大,最大併發量不超過1000;
專案上線後一般會換成uwsgi來提高最大併發量,前面還會加nginx進行反向代理;
-
WSGI,wsgiref 和 uwsgi 是什麼關係?
WSGI是協議,wsgiref和uwsgi是實現該協議的功能模組。
Django 簡介以及基本操作
1、MTV 模型 與 MVC 模型
MVC模型
Web伺服器開發領域裡著名的MVC模式,將web應用分為以下三層:
- 模型(Model)
- 檢視(View)
- 控制器(Controller)
以上三層之間以一種外掛式的、鬆耦合的方式連線在一起:
模型負責業務物件與資料庫的對映(ORM)
檢視負責與使用者的互動(頁面)
控制器接受使用者的輸入呼叫模型和檢視完成使用者的請求。
其示意圖如下所示:
MTV模型
Django的MTV模式本質上和MVC是一樣的,也是為了各元件間保持鬆耦合關係,只是定義上有些許不同,Django的MTV分別是指:
- M 代表模型(Model): 負責業務物件和資料庫的關係對映(ORM)。
- T 代表模板 (Template):負責如何把頁面展示給使用者(html)。
- V 代表檢視(View): 負責業務邏輯,並在適當時候呼叫Model和Template。
除了以上三層之外,還需要一個URL分發器,它的作用是將一個個URL的頁面請求分發給不同的View處理,View再呼叫相應的Model和Template。
Django 使用MTV模型
2、基本操作
在windows cmd命令列介面下操作
切換到響應目錄中
建立diango專案:(mysite 是專案名稱)
django-admin startproject mysite
切換到 mysite 專案目錄中
建立應用:(app01是應用名稱)
python manage.py startapp app01
啟動django專案:
python manage.py runserver 8080
runserver 預設為本機(127.0.0.1),後面跟的8080為埠號
pycharm 操作
新建專案時選擇django 即可
新建Django專案的目錄名:
Django 必會三板斧
from django.shortcuts import HttpResponse, render, redirect
HttpResponse
內部傳入一個字串引數,返回給瀏覽器。
例如:
def index(request):
# 業務邏輯程式碼
return HttpResponse("OK")
render
除request引數外還接受一個待渲染的模板檔案和一個儲存具體資料的字典引數。
將資料填充進模板檔案,最後把結果返回給瀏覽器。(類似於我們上面用到的jinja2)
例如:
def index(request):
# 業務邏輯程式碼
return render(request, "index.html", {"name": "alex", "hobby": ["燙頭", "泡吧"]})
redirect
接受一個URL引數,表示跳轉到指定的URL。
例如:
def index(request):
# 業務邏輯程式碼
return redirect("/home/")
啟動Django報錯:
Django 啟動時報錯 “UnicodeEncodeError ...”
報這個錯誤通常是因為計算機名為中文,改成英文的計算機名重啟下電腦就可以了。
Django 啟動報錯“SyntaxError: Generator expression must be parenthesized”
報這個錯很大可能是因為使用了Python3.7.0,而目前(2018-06-12)Python3.7.0和Django還有點相容性問題,換回Python3.6的環境即可。