Django準備知識-web應用、http協議、web框架、Django簡介
一、web應用
Web應用程式是一種可以通過web訪問的應用程式(web應用本質是基於socket實現的應用程式),程式的最大好處是使用者很容易訪問應用程式,使用者只需要有瀏覽器即可,不需要再安裝其他軟體。應用程式有兩種模式C/S、B/S。C/S是客戶端/伺服器端程式,也就是說這類程式一般獨立執行。而B/S就是瀏覽器端/伺服器端應用程式,這類應用程式一般藉助谷歌,火狐等瀏覽器來執行。WEB應用程式一般是B/S模式。Web應用程式首先是“應用程式”,和用標準的程式語言,如java,python等編寫出來的程式沒有什麼本質上的不同。在網路程式設計的意義下,瀏覽器是一個socket客戶端,伺服器是一個socket服務端。
如下程式碼是一個python寫的服務端程式碼,可以用瀏覽器當客戶端去訪問該服務端,理解web服務:
import socket def handle_request(conn): request_data = conn.recv(1024) print("request_data: ", request_data) # 觀察並分析request_data值 conn.send("HTTP/1.1 200 OK\r\nstatus: 200\r\nContent-Type:text/html\r\n\r\n<h1>Hello, World!</h1>".encode("utf8")) # 響應首行\r\n響應頭(可以有多個鍵值對,以\r\n分隔)\r\n\r\n響應體 def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('localhost', 8812)) sock.listen(5) while True: print("the server is waiting for client-connection....") conn, addr = sock.accept() handle_request(conn) conn.close() if __name__ == '__main__': main()
二、http協議
1、http協議簡介
HTTP協議是Hyper Text Transfer Protocol(超文字傳輸協議)的縮寫,是用於全球資訊網(WWW:World Wide Web)伺服器與本地瀏覽器之間傳輸超文字的傳送協議。
HTTP是一個屬於應用層的面向物件的協議,由於其簡捷、快速的方式,適用於分散式超媒體資訊系統。它於1990年提出,經過幾年的使用與發展,得到不斷地完善和擴充套件。HTTP協議工作於客戶端-服務端架構上。瀏覽器作為HTTP客戶端通過URL向HTTP服務端即WEB伺服器傳送所有請求。Web伺服器根據接收到的請求,向客戶端傳送響應資訊。
2、http協議特性
(1)基於TCP/IP
HTTP協議是基於TCP/IP協議之上的應用層協議。
(2)基於請求-響應模式
HTTP協議規定,請求從客戶端發出,最後伺服器端響應該請求並返回。換句話說,肯定是先從客戶端開始建立通訊的,伺服器端在沒有接收到請求之前不會發送響應。
(3)無狀態儲存
HTTP是一種不儲存狀態,即無狀態(stateless)協議。HTTP協議自身不對請求和響應之間的通訊狀態進行儲存。也就是說在HTTP這個級別,協議對於傳送過的請求或響應都不做持久化處理。
使用HTTP協議,每當有新的請求傳送時,就會有對應的新響應產生。協議本身並不保留之前一切的請求或響應報文的資訊。這是為了更快地處理大量事務,確保協議的可伸縮性,而特意把HTTP協議設計成如此簡單的。可是,隨著Web的不斷髮展,因無狀態而導致業務處理變得棘手的情況增多了。比如,使用者登入到一家購物網站,即使他跳轉到該站的其他頁面後,也需要能繼續保持登入狀態。針對這個例項,網站為了能夠掌握是誰送出的請求,需要儲存使用者的狀態。HTTP/1.1雖然是無狀態協議,但為了實現期望的保持狀態功能,於是引入了Cookie技術。有了Cookie再用HTTP協議通訊,就可以管理狀態了。有關Cookie的詳細內容稍後講解。
(4)無連線
無連線的含義是限制每次連線只處理一個請求。伺服器處理完客戶的請求,並收到客戶的應答後,即斷開連線。採用這種方式可以節省傳輸時間。
3、http請求協議與響應協議
http協議包含由瀏覽器傳送資料到伺服器需要遵循的請求協議與伺服器傳送資料到瀏覽器需要遵循的響應協議。用於HTTP協議互動的信被為HTTP報文。請求端(客戶端)的HTTP報文做請求報文,響應端(伺服器端)的做響應報文。HTTP報文字身是由多行資料構成的字串文字。
(1)請求協議
請求格式,如圖:
請求方式:get與post
a、GET提交的資料會放在URL中的路徑之後,以?分割路徑和傳輸資料,引數之間以&相連,如EditBook?name=test&pwd=123;POST方法是把提交的資料放在HTTP包的請求體中;
b、GET提交的資料大小有限制(因為瀏覽器對URL的長度有限制),而POST方法提交的資料沒有限制(即POST方法才有請求體);
c、GET與POST請求在服務端獲取請求資料方式不同;
示例:GET / HTTP/1.1\r\n Host: 127.0.0.1:8812\r\nUser-Agent: Mozilla/5.0...\r\n\r\n
(2)響應協議
響應格式,如圖:
示例:HTTP/1.1 200 OK\r\nstatus:200\r\nContent-Type:text/html\r\n\r\n<h1>Hello</h1>
響應狀態碼:狀態碼的職責是當客戶端向伺服器端傳送請求時, 描述返回的請求結果。藉助狀態碼,使用者可以知道伺服器端是正常處理了請求,還是出現了錯誤。狀態碼(如:200 OK)以3位數字和原因短語組成。數字中的第一位指定了響應類別,後兩位無分類。響應類別有以下5種:
演示例項:
import socket sock = socket.socket() sock.bind(("127.0.0.1",8808)) sock.listen(5) while 1: print("server waiting.....") conn,addr = sock.accept() data = conn.recv(1024) print("request-data",data) # 讀取html檔案 with open("login.html","rb") as f: data = f.read() conn.send((b"HTTP/1.1 200 OK\r\n\r\n%s"%data)) conn.close()
login.html檔案:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="" method="post"> 使用者名稱 <input type="text" name="user"> 密碼 <input type="password" name="pwd"> <input type="submit"> </form> </body> </html>
三、web框架
Web框架(Web framework)是一種開發框架,用來支援動態網站、網路應用和網路服務的開發。大多數的web框架提供了一套開發和部署網站的方式,也為web行為提供了一套通用的方法。web框架已經實現了很多功能,開發人員使用框架提供的方法並且完成自己的業務邏輯,就能快速開發web應用了。瀏覽器和伺服器的是基於HTTP協議進行通訊的。也可以說web框架就是在以上十幾行程式碼基礎張擴展出來的,有很多簡單方便使用的方法,大大提高了開發的效率。
1、wsgiref模組
最簡單的Web應用就是先把HTML用檔案儲存好,用一個現成的HTTP伺服器軟體,接收使用者請求,從檔案中讀取HTML,返回。
如果要動態生成HTML,就需要把上述步驟自己來實現。不過,接受HTTP請求、解析HTTP請求、傳送HTTP響應都是苦力活,如果我們自己來寫這些底層程式碼,還沒開始寫動態HTML呢,就得花個把月去讀HTTP規範。
正確的做法是底層程式碼由專門的伺服器軟體實現,我們用Python專注於生成HTML文件。因為我們不希望接觸到TCP連線、HTTP原始請求和響應格式,所以,需要一個統一的介面協議來實現這樣的伺服器軟體,讓我們專心用Python編寫Web業務。這個介面就是WSGI:Web Server Gateway Interface。而wsgiref模組就是python基於wsgi協議開發的服務模組。
閱讀如下程式碼,理解wsgiref模組用法:
from wsgiref.simple_server import make_server def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return [b'<h1>Hello, web!</h1>'] httpd = make_server('', 8080, application) print('Serving HTTP on port 8080...') # 開始監聽HTTP請求: httpd.serve_forever()
總結:wsgiref模組的主要作用是拆請求協議的包和封裝響應格式。
2、DIY一個web框架
目錄結構如下:
`
import pymysql conn = pymysql.connect(host='127.0.0.1',port= 3306,user = 'root',password='',db='mydb') cur = conn.cursor() sql=''' create table userinfo( id INT PRIMARY KEY, name VARCHAR(32), password VARCHAR(32) ) ''' cur.execute(sql) conn.commit() cur.close() conn.close()models.py檔案
from wsgiref.simple_server import make_server from app01.views import * import urls def routers(): URLpattern = urls.URLpattern return URLpattern def applications(environ,start_response): path = environ.get("PATH_INFO") start_response('200 OK', [('Content-Type', 'text/html'),('Charset', 'utf8')]) urlpattern = routers() func = None for item in urlpattern: if path == item[0]: func = item[1] break if func: return [func(environ)] else: return [b"<h1>404!<h1>"] if __name__ == '__main__': server = make_server("",8080,applications) print("Serving HTTP on port 8080...") server.serve_forever()manage.py(啟動檔案)
from app01.views import * URLpattern = ( ("/login/", login), )urls.py檔案
import pymysql from urllib.parse import parse_qs def login(environ): if environ.get("REQUEST_METHOD") == "POST": try: request_body_size = int(environ.get('CONTENT_LENGTH', 0)) except (ValueError): request_body_size = 0 request_body = environ['wsgi.input'].read(request_body_size) data = parse_qs(request_body) user = data.get(b"user")[0].decode("utf8") pwd = data.get(b"pwd")[0].decode("utf8") # 連線資料庫 conn = pymysql.connect(host='127.0.0.1',port= 3306,user = 'root',password='',db='mydb') # 建立遊標 cur = conn.cursor() SQL = "select * from userinfo WHERE NAME ='%s' AND PASSWORD ='%s'"%(user,pwd) cur.execute(SQL) if cur.fetchone(): f = open("templates/backend.html","rb") data = f.read() data = data.decode("utf8") return data.encode("utf8") else: print("OK456") return b"user or pwd is wrong" else: f = open("templates/login.html", "rb") data = f.read() f.close() return dataviews檔案
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h4>登入頁面</h4> <form action="" method="post"> 使用者名稱 <input type="text" name="user"> 密碼 <input type="text" name="pwd"> <input type="submit"> </form> </body> </html>login.html檔案
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h4>welcome to myweb!</h4> </body> </html>backend.html檔案
myweb這個package就是一個web框架,下載這個web框架就可以快速實現一些簡單的web功能,比如檢視時間。
四、Django簡介
1、MVC與MTV模型
a、MVC
Web伺服器開發領域裡著名的MVC模式,所謂MVC就是把Web應用分為模型(M),控制器(C)和檢視(V)三層,他們之間以一種外掛式的、鬆耦合的方式連線在一起,模型負責業務物件與資料庫的對映(ORM),檢視負責與使用者的互動(頁面),控制器接受使用者的輸入呼叫模型和檢視完成使用者的請求,其示意圖如下所示:
b、MTV
Django的MTV模式本質上和MVC是一樣的,也是為了各元件間保持鬆耦合關係,只是定義上有些許不同,Django的MTV分別是值:
M 代表模型(Model): 負責業務物件和資料庫的關係對映(ORM)。
T 代表模板 (Template):負責如何把頁面展示給使用者(html)。
V 代表檢視(View): 負責業務邏輯,並在適當時候呼叫Model和Template。
除了以上三層之外,還需要一個URL分發器,它的作用是將一個個URL的頁面請求分發給不同的View處理,View再呼叫相應的Model和Template,MTV的響應模式如下所示:
一般是使用者通過瀏覽器向我們的伺服器發起一個請求(request),這個請求回去訪問檢視函式,(如果不涉及到資料呼叫,那麼這個時候檢視函式返回一個模板也就是一個網頁給使用者),檢視函式呼叫模型,模型去資料庫查詢資料,然後逐級返回,檢視函式把返回的資料填充到模板中空格中,最後返回網頁給使用者。
2、Django的下載與基本命令
(1)下載Django
pip3 install django # 不寫版本號,預設下載最新版本
pip3 install django==2.1.2 # 指定版本
(2)建立一個django project(django-admin.exe所在目錄要加入環境變數)
django-admin startproject mysite
注意:此命令在哪個目錄下執行,django專案就建在了哪個目錄下
執行後,當前目錄會生成mysite的工程,目錄結構如下:
manage.py -- Django專案裡面的工具,通過它可以呼叫django shell和資料庫等。
settings.py -- 包含了專案的預設設定,包括資料庫資訊,除錯標誌以及其他一些工作的變數。
urls.py -- 負責把URL模式對映到應用程式。
(3)在mysite目錄下建立應用(一定要先進入manage.py所在目錄,再執行如下命令)
python manage.py startapp blog
注意:一個專案中有多個應用,每個應用都有自己的業務邏輯
執行後,mysite目錄下會生成blog這個應用,目錄如下:
(4)啟動django專案(不寫埠,預設是8000)
python manage.py runserver 8080
這樣我們的django就啟動起來了!當我們訪問:http://127.0.0.1:8080/時就可以看到:
3、基於Django實現的一個簡單示例
urls檔案(url控制器):
from django.contrib import admin from django.urls import path from blog import views urlpatterns = [ path(r'^admin/$', admin.site.urls), path(r'^index/$', views.index), }
views檔案(檢視):
from django.shortcuts import render # Create your views here. import datetime def index(request): now = datetime.datetime.now() ctime = now.strftime("%Y-%m-%d %X") return render(request,"index.html",{"ctime":ctime})
index.html(模板檔案)- 若沒有templates目錄則手動建立,其中放html檔案
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h4>當前時間:{{ ctime }}</h4> </body> </html>
通過瀏覽器訪問127.0.0.1:8080/index/,檢視效果。
注意:每一個檢視函式都傳一個request形參,封裝了請求協議,並返回HttpResponse物件。
五、補充
1、url的組成
協議://域名:埠號/路徑?引數(鍵值對,如:user=name&pwd=123)
示例:https://www.baidu.com/s?wd=alex
2、Django框架問題
用命令建立完成後沒有templates資料夾(存放html檔案),需要手動建立,並且有些版本沒有配置templates路徑,需手動配置,方法如下:
找到settings.py檔案中的TEMPLATES列表中的 'DIRS': [os.path.join(BASE_DIR, "templates")]
3、當使用django時,如果頁面遇到forbidden錯誤時(post提交容易發生),就去settings.py檔案中找到MIDDLEWARE列表的第3項'django.middleware.csrf.CsrfViewMiddleware',將其註釋掉即可。