全部的Web應用本質上就是一個socket服務端,而用戶的瀏覽器就是一個socket客戶端。 這樣咱們就能夠本身實現Web框架了。咱們定義一個socket server端程序,與瀏覽器(client端)進行互交試試css
import socket sk = socket.socket() sk.bind(("127.0.0.1", 8001)) sk.listen() while True: conn, addr = sk.accept() data = conn.recv(8096) print(data) # 將瀏覽器發來的消息打印出來 conn.send(b"OK") conn.close()
b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8001\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nDNT: 1\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\nCookie: csrftoken=RKBXh1d3M97iz03Rpbojx1bR6mhHudhyX5PszUxxG3bOEwh1lxFpGOgWN93ZH3zv\r\n\r\n'
服務端收到了http的請求頭,如此就能夠和客戶端進行互交了。因此能夠說Web服務本質上都是在這十幾行代碼基礎上擴展出來的,只要請求和響應知足必定的規範(http協議),就能夠實現咱們寫的server端和client端進行互交了。html
HTTP協議詳解:http://www.javashuo.com/article/p-ojnddlxm-o.htmlpython
import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('127.0.0.1', 8000)) sock.listen() while True: conn, addr = sock.accept() data = conn.recv(8096) # 給回覆的消息加上響應狀態行 conn.send(b"HTTP/1.1 200 OK\r\n\r\n") # 包括響應行和響應頭和換行 conn.send(b"OK") # 回覆響應正文 conn.close()
此時在訪問127.0.0.1:8000便可獲得OK界面web
如何讓咱們的Web服務根據用戶請求的URL不一樣而返回不一樣的內容呢?數據庫
""" 根據URL中不一樣的路徑返回不一樣的內容,返回獨立的HTML頁面 """ import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) # 綁定IP和端口 sk.listen() # 監聽 # 將返回不一樣的內容部分封裝成函數 def index(request): # 讀取index.html頁面的內容 with open("index.html", "r", encoding="utf8") as f: s = f.read() # 返回字節數據 return bytes(s, encoding="utf8") def home(request): 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()
這樣便可實現根據不一樣的url返回不一樣的界面express
這網頁可以顯示出來了,可是都是靜態的啊。頁面的內容都不會變化的,我想要的是動態網站。django
沒問題,我也有辦法解決。我選擇使用字符串替換來實現這個需求。(這裏使用時間戳來模擬動態的數據)flask
""" 根據URL中不一樣的路徑返回不一樣的內容--函數進階版 返回HTML頁面 讓網頁動態起來 """ import socket import time sk = socket.socket() sk.bind(("127.0.0.1", 8080)) # 綁定IP和端口 sk.listen() # 監聽 # 將返回不一樣的內容部分封裝成函數 def index(request): 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(request): 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()
本質到這已經講完了,下面講框架的基礎設計模式
對於真實開發中的python web程序來講,通常會分爲兩部分:服務器程序和應用程序。瀏覽器
服務器程序負責對socket服務器進行封裝,並在請求到來時,對請求的各類數據進行整理。
應用程序則負責具體的邏輯處理。爲了方便應用程序的開發,就出現了衆多的Web框架,例如:Django、Flask、web.py 等。不一樣的框架有不一樣的開發方式,可是不管如何,開發出的應用程序都要和服務器程序配合,才能爲用戶提供服務。
這樣,服務器程序就須要爲不一樣的框架提供不一樣的支持。這樣混亂的局面不管對於服務器仍是框架,都是很差的。對服務器來講,須要支持各類不一樣框架,對框架來講,只有支持它的服務器才能被開發出的應用使用。
這時候,標準化就變得尤其重要。咱們能夠設立一個標準,只要服務器程序支持這個標準,框架也支持這個標準,那麼他們就能夠配合使用。一旦標準肯定,雙方各自實現。這樣,服務器能夠支持更多支持標準的框架,框架也可使用更多支持標準的服務器。
WSGI(Web Server Gateway Interface)就是一種規範,它定義了使用Python編寫的web應用程序或框架與web服務器程序之間的接口格式,實現web應用程序與web服務器程序間的解耦。
經常使用的WSGI服務器有uwsgi(性能比wsgiref好)、Gunicorn。而Python標準庫提供的獨立WSGI服務器叫wsgiref(本質是socket服務器),Django開發環境用的就是這個模塊來作服務器,Werkuzeug也是實現了wsgi的模塊(flask使用),下面wsgi左右的都是服務器,不過各自的功能不一樣,具體功能看下面的abc
web框架的本質:
socket服務端 與 瀏覽器的通訊
socket服務端功能劃分:
a. 負責與瀏覽器收發消息(socket通訊) --> wsgiref/uWsgi/gunicorn...
b. 根據用戶訪問不一樣的路徑執行不一樣的函數
c. 從HTML讀取出內容,而且完成字符串的替換 --> jinja2(模板語言)
Python中 Web框架的分類:
按上面三個功能劃分:
1. 框架自帶a,b,c --> Tornado
2. 框架自帶b和c,使用第三方的a --> Django 第三方的a是wsgiref
3. 框架自帶b,使用第三方的a和c --> Flask 第三方的a是Werkzeug,c是jinja2
按另外一個維度來劃分:
1. Django --> 大而全(你作一個網站能用到的它都有)
2. 其餘 --> Flask 輕量級
MVC,全名是Model View Controller,是軟件工程中的一種軟件架構模式,把軟件系統分爲三個基本部分:模型(Model)、視圖(View)和控制器(Controller),具備耦合性低、重用性高、生命週期成本低等優勢。
Django框架的設計模式借鑑了MVC框架的思想,也是分紅三部分,來下降各個部分之間的耦合性。
Django框架的不一樣之處在於它拆分的三部分爲:Model(模型)、Template(模板)和View(視圖),也就是MTV框架。
Model(模型):負責業務對象與數據庫的對象(ORM)
Template(模版):負責如何把頁面展現給用戶
View(視圖):負責業務邏輯,並在適當的時候調用Model和Template
此外,Django還有一個urls分發器,它的做用是將一個個URL的頁面請求分發給不一樣的view處理,view再調用相應的Model和Template
0. 啓動服務端,等待客戶端(用戶的瀏覽器)來鏈接
1. 在瀏覽器地址欄輸入URL,與服務端創建鏈接,瀏覽器發送請求
2. 服務端收到請求消息,解析請求消息,根據路徑和函數的對應關係,找到將要執行的函數
3. 執行函數,打開HTML文件,進行字符串替換,獲得一個最終要返回的HTML內容
4. 按照HTTP協議的消息格式要求,把HTML內容回覆給用戶瀏覽器(發送響應)
5. 瀏覽器收到響應的消息以後,按照HTML的規則渲染頁面.
6. 關閉鏈接
LTS爲官方長期維護的版本:
這裏有1.11版本的官方翻譯文檔,我看的時候官方翻譯的文檔沒有1.11版本的,只有2.0及之後的,若看2.0之後,直接去官方看便可
運行下面指令安裝完成便可使用django-admin命令查看
pip3 install django==1.11.11
執行完成會在當前目錄下安裝django
(一)命令行建立方式(不推薦使用)
1. cd到你要保存Django項目的目錄
2. Django-admin startproject 項目名 --> 會在當前目錄建立Django項目
django-admin startproject mysite
# 若Django未加入到環境變量,能夠到目錄下找django文件 H:\python\venvs\Mydjango\Scripts\django-admin startproject newdjango
(二)pycharm中建立django項目
1.首先你要有一個安裝了django的python解釋器(沒有的話pycharm通常也會幫忙建立,自動調用pip命令安裝django,個別版本會有問題)
1.若是是安裝的純淨的解釋器(官網直接下的):cd到解釋器安裝目錄下Script目錄的位置(裏面有pip.exe的那個),而後執行pip3 install django==1.11.11,這時你就有一個安裝了django的python解釋器
2.若是是pycharm中建立的虛擬環境,直接在虛擬環境的帶有python.exe的同級目錄下執行pip3 install django==1.11.11
3.若是是別的虛擬環境。。。。。我也不會
2.而後點擊新建項目(選擇安裝了django的python解釋器)
而後就能夠了,測試是否建立成功就在項目裏執行一下,而後點擊控制檯的連接,而後就能夠看到祝賀界面
也能夠在命令行界面啓動,保證本身保持和manage.py在同一目錄下,而後執行
python manage.py runserver
你應該會看到以下輸出:
Performing system checks... System check identified no issues (0 silenced). You have unapplied migrations; your app may not work properly until they are applied. Run 'python manage.py migrate' to apply them. 十月 23, 2018 - 15:50:53 Django version 2.1, using settings 'mysite.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
而後點擊控制檯的連接,而後就能夠看到祝賀界面
Django啓動:
Django項目在pycharm中啓動時,不要運行單個文件,要點擊綠色三角運行
命令行啓動
在項目的根目錄下(也就是有manage.py的那個目錄),運行:
python3 manage.py runserver IP:端口--> 在指定的IP和端口啓動
python3 manage.py runserver 端口 --> 在指定的端口啓動
python3 manage.py runserver --> 默認在本機的8000端口啓動
Django 啓動時報錯 「UnicodeEncodeError ...」
報這個錯誤一般是由於計算機名爲中文,改爲英文的計算機名重啓下電腦就能夠了。
Django 啓動報錯「SyntaxError: Generator expression must be parenthesized」
報這個錯很大多是由於使用了Python3.7.0,而目前(2018-06-12)Python3.7.0和Django還有點兼容性問題,換回Python3.6的環境便可。
剛開始學習時可在配置文件中暫時禁用csrf中間件,方便表單提交測試。
一、外層總目錄介紹
在執行完 django-admin startproject mysite 的建立
mysite/ # 項目根目錄 ├── manage.py # 管理文件,互交命令行工具 └── mysite # 項目目錄(純Python包) ├── __init__.py # Python包必帶 ├── settings.py # 配置 ├── urls.py # 路由 --> URL和函數(類)的對應關係 └── wsgi.py # runserver命令就使用wsgiref模塊作簡單的web server
這些文件是:
mysite/
根目錄僅僅是項目的一個容器。 它的名字與Django無關;能夠將其重命名爲你喜歡的任何內容。manage.py
:一個命令行工具,可使你用多種方式對Django項目進行交互。 你能夠在django-admin和manage.py中讀到關於manage.py
的全部細節。mysite/
目錄是你的項目的真正的Python包。 它是你導入任何東西時將須要使用的Python包的名字(例如 mysite.urls
)。mysite/__init__.py
:一個空文件,它告訴Python這個目錄應該被看作一個Python包。 若是你是Python初學者,請在官方Python文檔中閱讀關於python包的更多內容。mysite/settings.py
:該Django 項目的設置/配置。 Django settings 將告訴你這些設置如何工做。mysite/urls.py
:此Django項目的URL聲明;Django驅動的網站的「目錄」。 你能夠在URL dispatcher 中閱讀到更多關於URL的內容。mysite/wsgi.py
:用於你的項目的與WSGI兼容的Web服務器入口。 更多細節請參見如何使用WSGI部署。二、APP層目錄介紹
應用和項目的區別:
項目和應用之間有什麼不一樣? 應用是一個Web應用程序,它完成具體的事項 —— 好比一個博客系統、一個存儲公共檔案的數據庫或者一個簡單的投票應用。 一個項目是特定網站的配置和應用程序的集合。 一個項目能夠包含多個應用。 一個應用能夠運用到多個項目中去。
要建立你的應用,請確保與manage.py
在同一目錄中,並鍵入如下命令:
python manage.py startapp polls
這將建立一個目錄polls
,它的結構以下:
polls/ __init__.py admin.py apps.py migrations/ __init__.py models.py tests.py views.py
一、migrations目錄:此目錄記錄了數據庫變化狀況
二、admin.py文件: Django 爲咱們提供的後臺管理
三、apps.py文件:配置當前app
四、models.py文件:此文件用來定義數據庫表,ORM,寫指定的類,經過命令能夠建立數據庫結構
五、tests.py文件:此文件用於單元測試
六、urls.py文件:此文件是APP本身的路由規則所在的文件(上面目錄沒有,是二級路由時用,可手動建立)
七、views.py文件:此文件是視圖函數的代碼所在文件,關於視圖函數會在後面的博客中詳細介紹
三、靜態文件目錄
建立工程完成後,咱們須要在工程根目錄下建立一個「static」目錄用戶保存靜態文件。
關於靜態文件,在網站中,那些圖片、css、js等通常狀況下內容不會變化的文件都是靜態文件,咱們能夠把這些文件都放這個靜態文件目錄中。
靜態目錄建立完成後須要在settings.py文件中添加以下的配置:
STATIC_URL = '/static/' STATICFILES_DIRS = ( os.path.join(BASE_DIR,'static'), )
四、模板文件目錄
模板文件就是指那些html文件,在用戶訪問的過程當中,Django會將頁面上的數據套用到模板文件,渲染成一個完整的字符串而後返回給客戶端,這些模板文件存放在templates目錄中,關於模板文件以及模板語言的語法將會在後續的博客中詳細介紹。