Web開發的早期階段,開發者須要手動編寫每一個頁面,例如一個新聞門戶網站,天天都要修改它的HTML頁面,隨着網站規模和體量的增大,這種方式就變得極度糟糕。爲了解決這個問題,開發人員想到了用外部程序來爲Web服務器生成動態內容,也就是說HTML頁面以及頁面中的動態內容再也不經過手動編寫而是經過程序自動生成。最先的時候,這項技術被稱爲CGI(公共網關接口),固然隨着時間的推移,CGI暴露出的問題也愈來愈多,例如大量重複的樣板代碼,整體性能較爲低下等,所以在時代呼喚新英雄的背景下,PHP、ASP、JSP這類Web應用開發技術在上世紀90年代中後期如雨後春筍般涌現。一般咱們說的Web應用是指經過瀏覽器來訪問網絡資源的應用程序,由於瀏覽器的普及性以及易用性,Web應用使用起來方便簡單,免除了安裝和更新應用程序帶來的麻煩,並且也不用關心用戶到底用的是什麼操做系統,甚至不用區分是PC端仍是移動端。html
下圖向咱們展現了Web應用的工做流程,其中涉及到的術語以下表所示。前端
說明:相信有經驗的讀者會發現,這張圖中其實還少了不少東西,例如反向代理服務器、數據庫服務器、防火牆等,並且圖中的每一個節點在實際項目部署時多是一組節點組成的集羣。固然,若是你對這些沒有什麼概念也沒關係,繼續下去就好了,後面會給你們一一講解的。python
術語 | 解釋 |
---|---|
URL/URI | 統一資源定位符/統一資源標識符,網絡資源的惟一標識 |
域名 | 與Web服務器地址對應的一個易於記憶的字符串名字 |
DNS | 域名解析服務,能夠將域名轉換成對應的IP地址 |
IP地址 | 網絡上的主機的身份標識,經過IP地址能夠區分不一樣的主機 |
HTTP | 超文本傳輸協議,構建在TCP之上的應用級協議,萬維網數據通訊的基礎 |
反向代理 | 代理客戶端向服務器發出請求,而後將服務器返回的資源返回給客戶端 |
Web服務器 | 接受HTTP請求,而後返回HTML文件、純文本文件、圖像等資源給請求者 |
Nginx | 高性能的Web服務器,也能夠用做反向代理,負載均衡 和 HTTP緩存 |
這裏咱們稍微費一些筆墨來談談上面提到的HTTP。HTTP(超文本傳輸協議)是構建於TCP(傳輸控制協議)之上應用級協議,它利用了TCP提供的可靠的傳輸服務實現了Web應用中的數據交換。按照維基百科上的介紹,設計HTTP最初的目的是爲了提供一種發佈和接收HTML頁面的方法,也就是說這個協議是瀏覽器和Web服務器之間傳輸的數據的載體。關於這個協議的詳細信息以及目前的發展情況,你們能夠閱讀阮一峯老師的《HTTP 協議入門》、《互聯網協議入門》系列以及《圖解HTTPS協議》進行了解。下圖是我於2009年9月10日凌晨4點在四川省網絡通訊技術重點實驗室用開源協議分析工具Ethereal(抓包工具WireShark的前身)截取的訪問百度首頁時的HTTP請求和響應的報文(協議數據),因爲Ethereal截取的是通過網絡適配器的數據,所以能夠清晰的看到從物理鏈路層到應用層的協議數據。git
HTTP請求(請求行+請求頭+空行+[消息體]):程序員
HTTP響應(響應行+響應頭+空行+消息體):github
說明:希望這兩張如同泛黃的照片般的截圖能幫助你瞭解HTTP究竟是什麼樣子的。web
Python的Web框架有上百個,比它的關鍵字還要多。所謂Web框架,就是用於開發Web服務器端應用的基礎設施(一般指封裝好的模塊和一系列的工具)。事實上,即使沒有Web框架,咱們仍然能夠經過socket或CGI來開發Web服務器端應用,可是這樣作的成本和代價在實際開發中一般是不能接受的。經過Web框架,咱們能夠化繁爲簡,同時下降建立、更新、擴展應用程序的工做量。Python的Web框架中比較有名的有:Flask、Django、Tornado、Sanic、Pyramid、Bottle、Web2py、web.py等。正則表達式
在基於Python的Web框架中,Django是全部重量級選手中最有表明性的一位,開發者能夠基於Django快速的開發可靠的Web應用程序,由於它減小了Web開發中沒必要要的開銷,對經常使用的設計和開發模式進行了封裝,並對MVC架構提供了支持(MTV)。許多成功的網站和App都是基於Django框架構建的,國內比較有表明性的網站包括:知乎、豆瓣網、果殼網、搜狐閃電郵箱、101圍棋網、海報時尚網、背書吧、堆糖、手機搜狐網、咕咚、愛福窩、果庫等。shell
Django誕生於2003年,它是一個在真正的應用中成長起來的項目,由勞倫斯出版集團旗下在線新聞網站的內容管理系統(CMS)研發團隊編寫(主要是Adrian Holovaty和Simon Willison),以比利時的吉普賽爵士吉他手Django Reinhardt來命名,在2005年夏天做爲開源框架發佈。使用Django能用很短的時間構建出功能完備的網站,由於它代替程序員完成了全部乏味和重複的勞動,剩下真正有意義的核心業務給程序員,這一點就是對DRY(Don't Repeat Yourself)理念的最好踐行。數據庫
檢查Python環境:Django 1.11須要Python 2.7或Python 3.4以上的版本;Django 2.0須要Python 3.4以上的版本;Django 2.1須要Python 3.5以上的版本。
$ python3 --version
$ python3
>>> import sys
>>> sys.version
>>> sys.version_info
建立項目文件夾並切換到該目錄,例如咱們要實例一個OA(辦公自動化)項目。
$ mkdir oa
$ cd oa
建立並激活虛擬環境。
$ python3 -m venv venv
$ source venv/bin/activate
說明:上面使用了Python自帶的venv模塊完成了虛擬環境的建立,固然也可使用其餘的工具,例如:virtualenv或pipenv等。要激活虛擬環境,在Windows系統下是經過"venv/Scripts/activate"`執行批處理文件來實現。
更新包管理工具pip。
(venv)$ pip install -U pip
或
(venv)$ python -m pip install -U pip
注意:請注意終端提示符發生的變化,前面的
(venv)
說明咱們已經進入虛擬環境,而虛擬環境下的python和pip已是Python 3的解釋器和包管理工具了。
安裝Django。
(venv)$ pip install django
或指定版本號來安裝對應的Django的版本。
(venv)$ pip install django==1.11
檢查Django的版本。
(venv)$ python -m django --version
(venv)$ django-admin --version
或
(venv)$ python
>>> import django
>>> django.get_version()
固然,也能夠經過pip來查看安裝的依賴庫及其版本,如:
(venv)$ pip freeze
(venv)$ pip list
下圖展現了Django版本和Python版本的對應關係,若是在安裝時沒有指定版本號,將自動選擇最新的版本(在寫做這段內容時,最新的版本是2.0;目前最新的版本已經更新到2.2)。
Django版本 | Python版本 |
---|---|
1.8 | 2.七、3.二、3.三、3.四、3.5 |
1.九、1.10 | 2.七、3.四、3.5 |
1.11 | 2.七、3.四、3.五、3.六、3.7 |
2.0 | 3.四、3.五、3.六、3.7 |
2.一、2.2 | 3.五、3.六、3.7 |
使用django-admin
建立項目,項目命名爲oa。
(venv)$ django-admin startproject oa .
注意:上面的命令最後的那個點,它表示在當前路徑下建立項目。
執行上面的命令後看看生成的文件和文件夾,它們的做用以下所示:
manage.py
: 一個讓你用各類方式管理 Django 項目的命令行工具。oa/__init__.py
:一個空文件,告訴 Python 這個目錄應該被認爲是一個 Python 包。oa/settings.py
:Django 項目的配置文件。oa/urls.py
:Django 項目的 URL 聲明,就像你網站的「目錄」。oa/wsgi.py
:做爲你的項目的運行在 WSGI 兼容的Web服務器上的入口。啓動服務器運行項目。
(venv)$ python manage.py runserver
在瀏覽器中輸入http://127.0.0.1:8000訪問咱們的服務器,效果以下圖所示。
說明1:剛剛啓動的是Django自帶的用於開發和測試的服務器,它是一個用純Python編寫的輕量級Web服務器,但它並非真正意義上的生產級別的服務器,千萬不要將這個服務器用於和生產環境相關的任何地方。
說明2:用於開發的服務器在須要的狀況下會對每一次的訪問請求從新載入一遍Python代碼。因此你不須要爲了讓修改的代碼生效而頻繁的從新啓動服務器。然而,一些動做,好比添加新文件,將不會觸發自動從新加載,這時你得本身手動重啓服務器。
說明3:能夠經過
python manage.py help
命令查看可用命令列表;在啓動服務器時,也能夠經過python manage.py runserver 1.2.3.4:5678
來指定綁定的IP地址和端口。
說明4:能夠經過Ctrl+C來終止服務器的運行。
接下來咱們修改項目的配置文件settings.py,Django是一個支持國際化和本地化的框架,所以剛纔咱們看到的默認首頁也是支持國際化的,咱們將默認語言修改成中文,時區設置爲東八區。
(venv)$ vim oa/settings.py
# 此處省略上面的內容 # 設置語言代碼 LANGUAGE_CODE = 'zh-hans' # 設置時區 TIME_ZONE = 'Asia/Chongqing' # 此處省略下面的內容
刷新剛纔的頁面。
建立名爲hrs(人力資源系統)的應用,一個Django項目能夠包含一個或多個應用。
(venv)$ python manage.py startapp hrs
執行上面的命令會在當前路徑下建立hrs目錄,其目錄結構以下所示:
__init__.py
:一個空文件,告訴 Python 這個目錄應該被認爲是一個 Python 包。admin.py
:能夠用來註冊模型,用於在Django的管理界面管理模型。apps.py
:當前應用的配置。migrations
:存放與模型有關的數據庫遷移信息。
__init__.py
:一個空文件,告訴 Python 這個目錄應該被認爲是一個 Python 包。models.py
:存放應用的數據模型,即實體類及其之間的關係(MVC/MVT中的M)。tests.py
:包含測試應用各項功能的測試類和測試函數。views.py
:處理請求並返回響應的函數(MVC中的C,MVT中的V)。修改應用目錄下的視圖文件views.py。
(venv)$ vim hrs/views.py
from django.http import HttpResponse def index(request): return HttpResponse('<h1>Hello, Django!</h1>')
在應用目錄建立一個urls.py文件並映射URL。
(venv)$ touch hrs/urls.py
(venv)$ vim hrs/urls.py
from django.urls import path from hrs import views urlpatterns = [ path('', views.index, name='index'), ]
說明:上面使用的
path
函數是Django 2.x中新添加的函數,除此以外還可使用支持正則表達式的URL映射函數re_path
函數;Django 1.x中是用名爲url
函數來設定URL映射。
切換到項目目錄,修改該目錄下的urls.py文件,對應用中設定的URL進行合併。
(venv) $ vim oa/urls.py
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('hrs/', include('hrs.urls')), ]
從新運行項目,並打開瀏覽器中訪問http://localhost:8000/hrs。
(venv)$ python manage.py runserver
修改views.py生成動態內容。
(venv)$ vim hrs/views.py
from io import StringIO from django.http import HttpResponse depts_list = [ {'no': 10, 'name': '財務部', 'location': '北京'}, {'no': 20, 'name': '研發部', 'location': '成都'}, {'no': 30, 'name': '銷售部', 'location': '上海'}, ] def index(request): output = StringIO() output.write('<html>\n') output.write('<head>\n') output.write('\t<meta charset="utf-8">\n') output.write('\t<title>首頁</title>') output.write('</head>\n') output.write('<body>\n') output.write('\t<h1>部門信息</h1>\n') output.write('\t<hr>\n') output.write('\t<table>\n') output.write('\t\t<tr>\n') output.write('\t\t\t<th width=120>部門編號</th>\n') output.write('\t\t\t<th width=180>部門名稱</th>\n') output.write('\t\t\t<th width=180>所在地</th>\n') output.write('\t\t</tr>\n') for dept in depts_list: output.write('\t\t<tr>\n') output.write(f'\t\t\t<td align=center>{dept["no"]}</td>\n') output.write(f'\t\t\t<td align=center>{dept["name"]}</td>\n') output.write(f'\t\t\t<td align=center>{dept["location"]}</td>\n') output.write('\t\t</tr>\n') output.write('\t</table>\n') output.write('</body>\n') output.write('</html>\n') return HttpResponse(output.getvalue())
刷新頁面查看程序的運行結果。
上面經過拼接HTML代碼的方式生成動態視圖的作法在實際開發中是無能接受的,這一點你們必定可以想到。爲了解決這個問題,咱們能夠提早準備一個模板頁,所謂模板頁就是一個帶佔位符的HTML頁面,當咱們將程序中得到的數據替換掉頁面中的佔位符時,一個動態頁面就產生了。
咱們能夠用Django框架中template模塊的Template類建立模板對象,經過模板對象的render方法實現對模板的渲染。所謂的渲染就是用數據替換掉模板頁中的佔位符,固然這裏的渲染稱爲後端渲染,即在服務器端完成頁面的渲染再輸出到瀏覽器中,這種作法的主要壞處是當併發訪問量較大時,服務器會承受較大的負擔,因此今天有不少的Web應用都使用了前端渲染,即服務器只爲瀏覽器提供所需的數據(一般是JSON格式),在瀏覽器中經過JavaScript獲取這些數據並渲染到頁面上,這些內容在後面爲你們呈現。
Django框架經過shortcuts模塊的快捷函數render
簡化了渲染模板的操做,具體的用法以下所示。
先回到manage.py文件所在的目錄建立名爲templates文件夾。
(venv)$ mkdir templates
建立模板頁index.html。
(venv)$ touch templates/index.html
(venv)$ vim templates/index.html
<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>首頁</title> </head> <body> <h1>部門信息</h1> <hr> <table> <tr> <th>部門編號</th> <th>部門名稱</th> <th>所在地</th> </tr> {% for dept in depts_list %} <tr> <td>{{ dept.no }}</td> <td>{{ dept.name }}</td> <td>{{ dept.location }}</td> <tr> {% endfor %} </table> </body> </html>
在上面的模板頁中咱們使用了{{ greeting }}
這樣的模板佔位符語法,也使用了{% for %}
這樣的模板指令,這些都是Django模板語言(DTL)的一部分。若是對此不熟悉並沒關係,咱們會在後續的內容中進一步的講解,並且咱們剛纔也說到了,還有更好的選擇就是使用前端渲染,固然這是後話。
回到應用目錄,修改views.py文件。
(venv)$ vim hrs/views.py
from django.shortcuts import render depts_list = [ {'no': 10, 'name': '財務部', 'location': '北京'}, {'no': 20, 'name': '研發部', 'location': '成都'}, {'no': 30, 'name': '銷售部', 'location': '上海'}, ] def index(request): return render(request, 'index.html', {'depts_list': depts_list})
到此爲止,咱們尚未辦法讓views.py中的render
函數找到模板文件index.html,爲此咱們須要修改settings.py文件,配置模板文件所在的路徑。
切換到項目目錄修改settings.py文件。
(venv)$ vim oa/settings.py
# 此處省略上面的內容 TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] # 此處省略下面的內容
從新運行項目或直接刷新頁面查看結果。
(venv)$ python manage.py runserver
至此,咱們已經利用Django框架完成了一個很是小的Web應用,雖然它並無任何的實際價值,可是能夠經過這個項目對Django框架有一個感性的認識。固然,實際開發中咱們能夠用PyCharm來建立項目,若是使用專業版的PyCharm,能夠直接建立Django項目。使用PyCharm的好處在於編寫代碼時能夠得到代碼提示、錯誤修復、自動導入等功能,從而提高開發效率,可是專業版的PyCharm須要按年支付相應的費用,社區版的PyCharm中並未包含對Django框架直接的支持,可是咱們仍然可使用它來建立Django項目,只是在使用上沒有專業版的方便。關於PyCharm的使用,能夠參考《玩轉PyCharm》一文。
此外,學習Django最好的資料確定是它的官方文檔,除此以外圖靈社區出版的《Django基礎教程》也是很是適合初學者的讀物。