Python Web框架: Django基礎與項目搭建
框架要點
1. Web應用程序處理流程
2. Web程序框架的意義
-
用于搭建Web應用程序
-
免去不同Web應用相同代碼部分的重復編寫,只需關心Web應用核心的業務邏輯實現
3. Web應用程序的本質
-
接收并解析HTTP請求,獲取具體的請求信息
-
處理本次HTTP請求,即完成本次請求的業務邏輯處理
-
構造并返回處理結果——HTTP響應
4. Web框架學習方法
-
如何搭建工程程序
-
工程的組建
-
工程的配置
-
路由定義
-
視圖函數定義
-
-
如何獲取請求數據(操作request對象)
-
如何構造響應數據(構造response對象)
-
如何使用中間層
-
框架提供的其他功能組件的使用
-
數據庫
-
模板
-
admin
-
1. Django介紹
1. 簡介
-
Django,是用python語言寫的開源web開發框架,并遵循MVC設計。勞倫斯出版集團為了開發以新聞內容為主的網站,而開發出來了這個框架,于2005年7月在BSD許可證下發布。這個名稱來源于比利時的爵士音樂家DjangoReinhardt,他是一個吉普賽人,主要以演奏吉它為主,還演奏過小提琴等。由于Django在近年來的迅速發展,應用越來越廣泛,被著名IT開發雜志SDTimes評選為2013SDTimes100,位列"API、庫和框架"分類第6位,被認為是該領域的佼佼者。
-
Django的主要目的是簡便、快速的開發數據庫驅動的網站。它強調代碼復用,多個組件可以很方便的以"插件"形式服務于整個框架,Django有許多功能強大的第三方插件,你甚至可以很方便的開發出自己的工具包。這使得Django具有很強的可擴展性。它還強調快速開發和DRY(DoNotRepeatYourself)原則。
2. 特點
1. 重量級框架
對比Flask框架,Django原生提供了眾多的功能組件,讓開發更簡便快速。
-
提供項目工程管理的自動化腳本工具
-
數據庫ORM支持(對象關系映射,英語:Object Relational Mapping)
-
模板
-
表單
-
Admin管理站點
-
文件管理
-
認證權限
-
session機制
-
緩存
2. MVT模式
有一種程序設計模式叫MVC,其核心思想是分工、解耦,讓不同的代碼塊之間降低耦合,增強代碼的可擴展性和可移植性,實現向后兼容。
MVC模式說明
-
M全拼為Model,主要封裝對數據庫層的訪問,對數據庫中的數據進行增、刪、改、查操作。
-
V全拼為View,用于封裝結果,生成頁面展示的html內容。
-
C全拼為Controller,用于接收請求,處理業務邏輯,與Model和View交互,返回結果。
Django的MVT
-
M全拼為Model,與MVC中的M功能相同,負責和數據庫交互,進行數據處理。
-
V全拼為View,與MVC中的C功能相同,接收請求,進行業務處理,返回應答。
-
T全拼為Template,與MVC中的V功能相同,負責封裝構造要返回的html。
注:差異就在于黑線黑箭頭標識出來的部分
2. 工程搭建
Ubuntu版本
1. 環境安裝
1. 創建虛擬環境
mkvirtualenv django_py3_1.11 -p python3
注意需要聯網
2. 安裝Django
使用django 1.11.11版本,注意需要聯網
pip install django==1.11.11
3. 虛擬環境和pip的命令
# 虛擬環境
mkvirtualenv # 創建虛擬環境
rmvirtualenv # 刪除虛擬環境
workon # 進入虛擬環境、查看所有虛擬環境
deactivate # 退出虛擬環境
# pip
pip install # 安裝依賴包
pip uninstall # 卸載依賴包
pip list # 查看已安裝的依賴庫
2. 創建工程
在django中,項目工程目錄可以借助django提供的命令幫助我們創建。
1. 創建
創建工程的命令為:
django-admin startproject 工程名稱
例如:想要在桌面的code目錄中創建一個名為demo的項目工程,可執行如下命令:
cd ~/Desktop/code
django-admin startproject demo
執行后,會多出一個新目錄名為demo,此即為新創建的工程目錄。
2. 工程目錄說明
查看創建的工程目錄,結構如下
-
與項目同名的目錄,此處為demo。
-
settings.py 是項目的整體配置文件。
-
urls.py 是項目的URL配置文件。
-
wsgi.py 是項目與WSGI兼容的Web服務器入口。
-
manage.py 是項目管理文件,通過它管理項目。
3. 運行開發服務器
在開發階段,為了能夠快速預覽到開發的效果,django提供了一個純python編寫的輕量級web服務器,僅在開發階段使用。
運行服務器命令如下:
python manage.py runserver ip:端口
或:
python manage.py runserver
可以不寫IP和端口,默認IP是127.0.0.1,默認端口為8000。
啟動后可見如下信息:
在瀏覽器中輸入網址“127.0.0.1:8000”便可看到效果。
- django默認工作在調式Debug模式下,如果增加、修改、刪除文件,服務器會自動重啟。
- 按ctrl+c停止服務器。
3. 創建子應用
在Web應用中,通常有一些業務功能模塊是在不同的項目中都可以復用的,故在開發中通常將工程項目拆分為不同的子功能模塊,各功能模塊間可以保持相對的獨立,在其他工程項目中需要用到某個特定功能模塊時,可以將該模塊代碼整體復制過去,達到復用。
在Flask框架中也有類似子功能應用模塊的概念,即藍圖Blueprint。
Django的視圖編寫是放在子應用中的。
1. 創建
在django中,創建子應用模塊目錄仍然可以通過命令來操作,即:
python manage.py startapp 子應用名稱
manage.py 為上述創建工程時自動生成的管理文件。
例如,在剛才創建的demo工程中,想要創建一個用戶users子應用模塊,可執行:
cd ~/Desktop/code/demo
python manage.py startapp users
執行后,可以看到工程目錄中多出了一個名為users的子目錄。
2. 子應用目錄說明
查看此時的工程目錄,結構如下:
- admin.py 文件跟網站的后臺管理站點配置相關。
- apps.py 文件用于配置當前子應用的相關信息。
- migrations 目錄用于存放數據庫遷移歷史文件。
- models.py 文件用戶保存數據庫模型類。
- tests.py 文件用于開發測試用例,編寫單元測試。
- views.py 文件用于編寫Web應用視圖。
3. 注冊安裝子應用
創建出來的子應用目錄文件雖然被放到了工程項目目錄中,但是django工程并不能立即直接使用該子應用,需要注冊安裝后才能使用。
在工程配置文件settings.py中,INSTALLED_APPS項保存了工程中已經注冊安裝的子應用,初始工程中的INSTALLED_APPS如下:
注冊安裝一個子應用的方法,即是將子應用的配置信息文件apps.py中的Config類添加到INSTALLED_APPS列表中。
例如,將剛創建的users子應用添加到工程中,可在INSTALLED_APPS列表中添加**‘users.apps.UsersConfig’**。
4. 創建視圖
同Flask框架一樣,Django也用視圖來編寫Web應用的業務邏輯。
Django的視圖是定義在子應用的views.py中的。
1. 創建
打開剛創建的users模塊,在views.py中編寫視圖代碼。
from django.http import HttpResponse
def index(request):
"""
index視圖
:param request: 包含了請求信息的請求對象
:return: 響應對象
"""
return HttpResponse("hello the world!")
說明:
-
視圖函數的第一個傳入參數必須定義,用于接收Django構造的包含了請求數據的HttpReqeust對象,通常名為request。
-
視圖函數的返回值必須為一個響應對象,不能像Flask一樣直接返回一個字符串,可以將要返回的字符串數據放到一個HTTPResponse對象中。
2. 定義路由URL
(1) 在子應用中新建一個urls.py文件用于保存該應用的路由
(2) 在users/urls.py文件中定義路由信息
from django.conf.urls import url
from . import views
# urlpatterns是被django自動識別的路由列表變量
urlpatterns = [
# 每個路由信息都需要使用url函數來構造
# url(路徑, 視圖)
url(r'^index/$', views.index),
]
(3)在工程總路由demo/urls.py中添加子應用的路由數據
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls), # django默認包含的
# 添加
url(r'^users/', include('users.urls')),
]
- 使用include來將子應用users里的全部路由包含進工程路由中;
r’^users/’ 決定了users子應用的所有路由都已/users/開頭,如我們剛定義的視圖index,其 - 最終的完整訪問路徑為/users/index/。
include函數除了可以傳遞字符串之外,也可以直接傳遞應用的urls模塊,如
from django.conf.urls import url, include
from django.contrib import admin
import users.urls # 先導入應用的urls模塊
urlpatterns = [
url(r'^admin/', admin.site.urls),
# url(r'^users/', include('users.urls')),
url(r'^users/', include(users.urls)), # 添加應用的路由
]
(4)啟動運行
重新啟動django程序
python manage.py runserver
在瀏覽器中輸入網址127.0.0.1:8000/users/index/ 可看到返回的信息
3. 配置、靜態文件與路由
1. 配置文件
1. BASE_DIR
當前工程的根目錄,Django會依此來定位工程內的相關文件,我們也可以使用該參數來構造文件路徑。
2. DEBUG
調試模式,創建工程后初始值為True,即默認工作在調試模式下。
作用:
- Django程序出現異常時,向前端顯示詳細的錯誤追蹤信息,
注意:部署線上運行的Django不要運行在調式模式下,記得修改DEBUG=False。
3. 本地語言與時區
初始化的工程默認語言和時區為英語和UTC標準時區
LANGUAGE_CODE = 'en-us' # 語言
TIME_ZONE = 'UTC' # 時區
將語言和時區修改為中國大陸信息
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
2. 靜態文件
項目中的CSS、圖片、js都是靜態文件。一般會將靜態文件放到一個單獨的目錄中,以方便管理。在html頁面中調用時,也需要指定靜態文件的路徑,Django中提供了一種解析的方式配置靜態文件路徑。靜態文件可以放在項目根目錄下,也可以放在應用的目錄下,由于有些靜態文件在項目中是通用的,所以推薦放在項目的根目錄下,方便管理。
為了提供靜態文件,需要配置兩個參數:
- STATICFILES_DIRS=[] 存放查找靜態文件的目錄 接收的是 list
- STATIC_URL 訪問靜態文件的URL前綴
注意:
-
Django 僅在調試模式下(DEBUG=True)能對外提供靜態文件。
-
當DEBUG=False工作在生產模式時,Django不再對外提供靜態文件,需要是用collectstatic命令來收集靜態文件并交由其他靜態文件服務器來提供。
3. 路由說明
1. 路由定義位置
Django的主要路由信息定義在工程同名目錄下的urls.py文件中,該文件是Django解析路由的入口。
每個子應用為了保持相對獨立,可以在各個子應用中定義屬于自己的urls.py來保存該應用的路由。然后用主路由文件包含各應用的子路由數據。
除了上述方式外,也可將工程的全部路由信息都定義在主路由文件中,子應用不再設置urls.py。如:
from django.conf.urls import url
from django.contrib import admin
import users.views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^users/index/$', users.views.index)
]
2. 路由解析順序
Django在接收到一個請求時,從主路由文件中的urlpatterns列表中以由上至下的順序查找對應路由規則,如果發現規則為include包含,則再進入被包含的urls中的urlpatterns列表由上至下進行查詢。
值得關注的由上至下的順序,有可能會使上面的路由屏蔽掉下面的路由,帶來非預期結果。例如:
urlpatterns = [
url(r'^say', views.say),
url(r'^sayhello', views.sayhello),
]
即使訪問sayhello/路徑,預期應該進入sayhello視圖執行,但實際優先查找到了say路由規則也與sayhello/路徑匹配,實際進入了say視圖執行。
提示:
- 需要注意定義路由的順序,避免出現屏蔽效應。
3. 路由命名與reverse反解析(逆向)
(1)路由命名
在定義路由的時候,可以為路由命名,方便查找特定視圖的具體路徑信息。
① 在使用include函數定義路由時,可以使用namespace參數定義路由的命名空間,如
url(r'^users/', include('users.urls', namespace='users')),
命名空間表示,凡是users.urls中定義的路由,均屬于namespace指明的users名下。
命名空間的作用:
- 避免不同應用中的路由使用了相同的名字發生沖突,使用命名空間區別開。
② 在定義普通路由時,可以使用name參數指明路由的名字,如
urlpatterns = [
url(r'^index/$', views.index, name='index'),
url(r'^say', views.say, name='say'),
]
(2)reverse反解析
使用reverse函數,可以根據路由名稱,返回具體的路徑,如:
from django.urls import reverse # 注意導包路徑
def index(request):
return HttpResponse("hello the world!")
def say(request):
url = reverse('users:index') # 返回 /users/index/
print(url)
return HttpResponse('say')
-
對于未指明namespace的,reverse(路由name)
-
對于指明namespace的,reverse(命名空間namespace:路由name)
(4)路徑結尾斜線/的說明
Django中定義路由時,通常以斜線/結尾,其好處是用戶訪問不以斜線/結尾的相同路徑時,Django會把用戶重定向到以斜線/結尾的路徑上,而不會返回404不存在。如
urlpatterns = [
url(r'^index/$', views.index, name='index'),
]
用戶訪問 index 或者 index/ 網址,均能訪問到index視圖。
說明:
雖然路由結尾帶/能帶來上述好處,但是卻違背了HTTP中URL表示資源位置路徑的設計理念。
是否結尾帶/以所屬公司定義風格為準。
4. 請求與響應
1. 請求 request
利用HTTP協議向服務器傳參的途徑:
- 提取URL的特定部分,如/weather/beijing/2018,可以在服務器端的路由中用正則表達式截取;
- 查詢字符串(query string),形如key1=value1&key2=value2;
- 請求體(body)中發送的數據,比如表單數據、json、xml;
- 在http報文的頭(header)中。
1. URL路徑參數
在定義路由URL時,可以使用正則表達式提取參數的方法從URL中獲取請求參數,Django會將提取的參數直接傳遞到視圖的傳入參數中。
- 未命名參數按定義順序傳遞, 如
url(r'^weather/([a-z]+)/(\d{4})/$', views.weather),
def weather(request, city, year):
print('city=%s' % city)
print('year=%s' % year)
return HttpResponse('OK')
- 命名參數按名字傳遞,如
url(r'^weather/(?P<city>[a-z]+)/(?P<year>\d{4})/$', views.weather),
def weather(request, year, city):
print('city=%s' % city)
print('year=%s' % year)
return HttpResponse('OK')
2. Django中的QueryDict對象
定義在django.http.QueryDict
HttpRequest對象的屬性GET、POST都是QueryDict類型的對象
與python字典不同,QueryDict類型的對象用來處理同一個鍵帶有多個值的情況
-
方法get():根據鍵獲取值
-
如果一個鍵同時擁有多個值將獲取最后一個值;
-
如果鍵不存在則返回None值,可以設置默認值進行后續處理
dict.get('鍵',默認值) 可簡寫為 dict['鍵']
-
-
方法getlist():根據鍵獲取值,值以列表返回,可以獲取指定鍵的所有值
-
如果鍵不存在則返回空列表[],可以設置默認值進行后續處理
dict.getlist('鍵',默認值)
-
3. 查詢字符串Query String
獲取請求路徑中的查詢字符串參數(形如?k1=v1&k2=v2),可以通過request.GET屬性獲取,返回QueryDict對象。
# /qs/?a=1&b=2&a=3
def qs(request):
a = request.GET.get('a')
b = request.GET.get('b')
alist = request.GET.getlist('a')
print(a) # 3
print(b) # 2
print(alist) # ['1', '3']
return HttpResponse('OK')
重要:
- 查詢字符串不區分請求方式,即假使客戶端進行POST方式的請求,依然可以通過request.GET獲取請求中的查詢字符串數據。
4. 請求體
請求體數據格式不固定,可以是表單類型字符串,可以是JSON字符串,可以是XML字符串,應區別對待。
可以發送請求體數據的請求方式有POST、PUT、PATCH、DELETE。
Django默認開啟了CSRF防護,會對上述請求方式進行CSRF防護驗證,在測試時可以關閉CSRF防護機制,方法為在settings.py文件中注釋掉CSRF中間件,如:
(1)表單類型 Form Data
前端發送的表單類型的請求體數據,可以通過request.POST屬性獲取,返回QueryDict對象。
def get_body(request):
a = request.POST.get('a')
b = request.POST.get('b')
alist = request.POST.getlist('a')
print(a)
print(b)
print(alist)
return HttpResponse('OK')
重要:
- request.POST只能用來獲取POST方式的請求體表單數據。
(2)非表單類型 Non-Form Data
非表單類型的請求體數據,Django無法自動解析,可以通過request.body屬性獲取最原始的請求體數據,自己按照請求體格式(JSON、XML等)進行解析。request.body返回bytes類型。
例如 要獲取請求體中的如下JSON數據
{"a": 1, "b": 2}
可以進行如下方法操作:
import json
def get_body_json(request):
json_str = request.body
json_str = json_str.decode() # python3.6 無需執行此步
req_data = json.loads(json_str)
print(req_data['a'])
print(req_data['b'])
return HttpResponse('OK')
5. 請求頭
可以通過 request.META 屬性獲取請求頭headers中的數據,request.META為字典類型。
常見的請求頭如:
- CONTENT_LENGTH – The length of the request body (as a string).
- CONTENT_TYPE – The MIME type of the request body.
- HTTP_ACCEPT – Acceptable content types for the response.
- HTTP_ACCEPT_ENCODING – Acceptable encodings for the response.
- HTTP_ACCEPT_LANGUAGE – Acceptable languages for the response.
- HTTP_HOST – The HTTP Host header sent by the client.
- HTTP_REFERER – The referring page, if any.
- HTTP_USER_AGENT – The client’s user-agent string.
- QUERY_STRING – The query string, as a single (unparsed) string.
- REMOTE_ADDR – The IP address of the client.
- REMOTE_HOST – The hostname of the client.
- REMOTE_USER – The user authenticated by the Web server, if any.
- REQUEST_METHOD – A string such as “GET” or “POST”.
- SERVER_NAME – The hostname of the server.
- SERVER_PORT – The port of the server (as a string).
具體使用如:
def get_headers(request):
print(request.META['CONTENT_TYPE'])
return HttpResponse('OK')
6. 其他常用HttpRequest對象屬性
- method:一個字符串,表示請求使用的HTTP方法,常用值包括:‘GET’、‘POST’。
- user:請求的用戶對象。
- path:一個字符串,表示請求的頁面的完整路徑,不包含域名和參數部分。
- encoding:一個字符串,表示提交的數據的編碼方式。
- 如果為None則表示使用瀏覽器的默認設置,一般為utf-8。
- 這個屬性是可寫的,可以通過修改它來修改訪問表單數據使用的編碼,接下來對屬性的任何訪問將使用新的encoding值。
- FILES:一個類似于字典的對象,包含所有的上傳文件。
2. 響應 response
視圖在接收請求并處理后,必須返回HttpResponse對象或子對象。HttpRequest對象由Django創建,HttpResponse對象由開發人員創建。
1. HttpResponse
可以使用django.http.HttpResponse來構造響應對象。
HttpResponse(content=響應體, content_type=響應體數據類型, status=狀態碼)
也可通過HttpResponse對象屬性來設置響應體、狀態碼:
content:表示返回的內容。
status_code:返回的HTTP響應狀態碼。
響應頭可以直接將HttpResponse對象當做字典進行響應頭鍵值對的設置:
response = HttpResponse()
response['Itcast'] = 'Python' # 自定義響應頭Itcast, 值為Python
示例:
from django.http import HttpResponse
def demo_view(request):
return HttpResponse('itcast python', status=400)
或者
response = HttpResponse('itcast python')
response.status_code = 400
response['Itcast'] = 'Python'
return response
2 HttpResponse子類
Django提供了一系列HttpResponse的子類,可以快速設置狀態碼
- HttpResponseRedirect 301
- HttpResponsePermanentRedirect 302
- HttpResponseNotModified 304
- HttpResponseBadRequest 400
- HttpResponseNotFound 404
- HttpResponseForbidden 403
- HttpResponseNotAllowed 405
- HttpResponseGone 410
- HttpResponseServerError 500
3 JsonResponse
若要返回json數據,可以使用JsonResponse來構造響應對象,作用:
- 幫助我們將數據轉換為json字符串
- 設置響應頭Content-Type為 application/json
from django.http import JsonResponse
def demo_view(request):
return JsonResponse({'city': 'beijing', 'subject': 'python'})
4 redirect重定向
from django.shortcuts import redirect
def demo_view(request):
return redirect('/index.html')
3. Cookie
Cookie,有時也用其復數形式Cookies,指某些網站為了辨別用戶身份、進行session跟蹤而儲存在用戶本地終端上的數據(通常經過加密)。
Cookie是存儲在瀏覽器中的一段純文本信息,建議不要存儲敏感信息如密碼,因為電腦上的瀏覽器可能被其它人使用。
Cookie的特點
- Cookie以鍵值對Key-Value形勢進行信息的存儲。
- Cookie基于域名安全,不同域名的Cookie是不能互相訪問的
1 設置Cookie
可以通過HttpResponse對象中的set_cookie方法來設置cookie。
HttpResponse.set_cookie(cookie名, value=cookie值, max_age=cookie有效期)
- max_age 單位為秒,默認為None。如果是臨時cookie,可將max_age設置為None。
2 讀取Cookie
可以通過HttpRequest對象的COOKIES屬性來讀取本次請求攜帶的cookie值。request.COOKIES為字典類型。
4. Session
Session 的作用
Session 的作用就是它在 Web服務器上保持用戶的狀態信息供在任何時間從任何設備上的頁面進行訪問。因為瀏覽器不需要存儲任何這種信息,所以可以使用任何瀏覽器,即使是像 Pad 或手機這樣的瀏覽器設備。
保持會話狀態!
Session的特點
- 依賴cookies
- 存儲敏感、重要的信息
- 支持更多字節
- Session共享問題
1. Session配置和存儲
(1)啟用Session
Django項目默認啟用Session。
可以在settings.py文件中查看,如圖所示
如需禁用session,將上圖中的session中間件注釋掉即可。
(2)存儲方式
在settings.py文件中,可以設置session數據的存儲方式,可以保存在數據庫、本地緩存等。
(1)數據庫
存儲在數據庫中,如下設置可以寫,也可以不寫,這是默認存儲方式。
SESSION_ENGINE='django.contrib.sessions.backends.db'
如果存儲在數據庫中,需要在項INSTALLED_APPS中安裝Session應用。
數據庫中的表如圖所示:
表結構如下
由表結構可知,操作Session包括三個數據:鍵,值,過期時間。
(2)本地緩存
存儲在本機內存中,如果丟失則不能找回,比數據庫的方式讀寫更快。
SESSION_ENGINE='django.contrib.sessions.backends.cache'
(3)混合存儲
優先從本機內存中存取,如果沒有則從數據庫中存取。
SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
(4)Redis
在redis中保存session,需要引入第三方擴展,我們可以使用django-redis來解決。
① 安裝擴展
pip install django-redis
② 配置
在settings.py文件中做如下設置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"
注意:
如果redis的ip地址不是本地回環127.0.0.1,而是其他地址,訪問Django時,可能出現Redis連接錯誤,如下:
解決方法:
修改redis的配置文件,添加特定ip地址。
打開redis的配置文件
sudo vim /etc/redis/redis.conf
在如下配置項進行修改(如要添加10.211.55.5地址)
重新啟動redis服務
sudo service redis-server restart
2. Session操作
通過HttpRequest對象的session屬性進行會話的讀寫操作。
(1)以鍵值對的格式寫session
request.session['鍵']=值
(2)根據鍵讀取值
request.session.get('鍵',默認值)
(3)清除所有session,在存儲中刪除值部分
request.session.clear()
(4)清除session數據,在存儲中刪除session的整條數據
request.session.flush()
(5)刪除session中的指定鍵及值,在存儲中只刪除某個鍵及對應的值
del request.session['鍵']
(6)設置session的有效期
request.session.set_expiry(value)
- 如果value是一個整數,session將在value秒沒有活動后過期。
- 如果value為0,那么用戶session的Cookie將在用戶的瀏覽器關閉時過期。
- 如果value為None,那么session有效期將采用系統默認值,默認為兩周,可以通過在settings.py中設置SESSION_COOKIE_AGE來設置全局默認值。
5. 類視圖與中間件
1. 類視圖
1. 類視圖引入
以函數的方式定義的視圖稱為函數視圖,函數視圖便于理解。但是遇到一個視圖對應的路徑提供了多種不同HTTP請求方式的支持時,便需要在一個函數中編寫不同的業務邏輯,代碼可讀性與復用性都不佳。
def register(request):
"""處理注冊"""
# 獲取請求方法,判斷是GET/POST請求
if request.method == 'GET':
# 處理GET請求,返回注冊頁面
return render(request, 'register.html')
else:
# 處理POST請求,實現注冊邏輯
return HttpResponse('這里實現注冊邏輯')
在Django中也可以使用類來定義一個視圖,稱為類視圖。
使用類視圖可以將視圖對應的不同請求方式以類中的不同方法來區別定義。如下所示:
from django.views.generic import View
class RegisterView(View):
"""類視圖:處理注冊"""
def get(self, request):
"""處理GET請求,返回注冊頁面"""
return render(request, 'register.html')
def post(self, request):
"""處理POST請求,實現注冊邏輯"""
return HttpResponse('這里實現注冊邏輯')
類視圖的好處:
- 代碼可讀性好
- 類視圖相對于函數視圖有更高的復用性, 如果其他地方需要用到某個類視圖的某個特定邏輯,直接繼承該類視圖即可
2. 類視圖使用
定義類視圖需要繼承自Django提供的父類View,可使用 from django.views.generic import View 或者 from django.views.generic.base import View 導入,定義方式如上所示。
配置路由時,使用類視圖的as_view()方法來添加。
urlpatterns = [
# 視圖函數:注冊
# url(r'^register/$', views.register, name='register'),
# 類視圖:注冊
url(r'^register/$', views.RegisterView.as_view(), name='register'),
]
3. 類視圖原理
@classonlymethod
def as_view(cls, **initkwargs):
"""
Main entry point for a request-response process.
"""
...省略代碼...
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
# 調用dispatch方法,按照不同請求方式調用不同請求方法
return self.dispatch(request, *args, **kwargs)
...省略代碼...
# 返回真正的函數視圖
return view
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
-
1.調用流程 as_view–>view–>dispatch
-
2.getattr(‘對象’,‘字符串’)
4. 類視圖使用裝飾器
為類視圖添加裝飾器,可以使用兩種方法。
為了理解方便,我們先來定義一個為函數視圖準備的裝飾器(在設計裝飾器時基本都以函數視圖作為考慮的被裝飾對象),及一個要被裝飾的類視圖。
def my_decorator(func):
def wrapper(request, *args, **kwargs):
print('自定義裝飾器被調用了')
print('請求路徑%s' % request.path)
return func(request, *args, **kwargs)
return wrapper
class DemoView(View):
def get(self, request):
print('get方法')
return HttpResponse('ok')
def post(self, request):
print('post方法')
return HttpResponse('ok')
(1)在URL配置中裝飾
urlpatterns = [
url(r'^demo/$', my_decorate(DemoView.as_view()))
]
此種方式最簡單,但因裝飾行為被放置到了url配置中,單看視圖的時候無法知道此視圖還被添加了裝飾器,不利于代碼的完整性,不建議使用。
此種方式會為類視圖中的所有請求方法都加上裝飾器行為(因為是在視圖入口處,分發請求方式前)。
(2)在類視圖中裝飾
在類視圖中使用為函數視圖準備的裝飾器時,不能直接添加裝飾器,需要使用method_decorator將其轉換為適用于類視圖方法的裝飾器。
method_decorator裝飾器使用name參數指明被裝飾的方法
# 為全部請求方法添加裝飾器
@method_decorator(my_decorator, name='dispatch')
class DemoView(View):
def get(self, request):
print('get方法')
return HttpResponse('ok')
def post(self, request):
print('post方法')
return HttpResponse('ok')
# 為特定請求方法添加裝飾器
@method_decorator(my_decorator, name='get')
class DemoView(View):
def get(self, request):
print('get方法')
return HttpResponse('ok')
def post(self, request):
print('post方法')
return HttpResponse('ok')
如果需要為類視圖的多個方法添加裝飾器,但又不是所有的方法(為所有方法添加裝飾器參考上面例子),可以直接在需要添加裝飾器的方法上使用method_decorator,如下所示
from django.utils.decorators import method_decorator
# 為特定請求方法添加裝飾器
class DemoView(View):
@method_decorator(my_decorator) # 為get方法添加了裝飾器
def get(self, request):
print('get方法')
return HttpResponse('ok')
@method_decorator(my_decorator) # 為post方法添加了裝飾器
def post(self, request):
print('post方法')
return HttpResponse('ok')
def put(self, request): # 沒有為put方法添加裝飾器
print('put方法')
return HttpResponse('ok')
5. 類視圖Mixin擴展類
使用面向對象多繼承的特性,可以通過定義父類(作為擴展類),在父類中定義想要向類視圖補充的方法,類視圖繼承這些擴展父類,便可實現代碼復用。
定義的擴展父類名稱通常以Mixin結尾。
舉例如下:
class MyDecoratorMixin(object):
@classmethod
def as_view(cls, *args, **kwargs):
view = super().as_view(*args, **kwargs)
view = my_decorator(view)
return view
class DemoView(MyDecoratorMixin, View):
def get(self, request):
print('get方法')
return HttpResponse('ok')
def post(self, request):
print('post方法')
return HttpResponse('ok')
class ListModelMixin(object):
"""
list擴展類
"""
def list(self, request, *args, **kwargs):
...
class CreateModelMixin(object):
"""
create擴展類
"""
def create(self, request, *args, **kwargs):
...
class BooksView(CreateModelMixin, ListModelMixin, View):
"""
同時繼承兩個擴展類,復用list和create方法
"""
def get(self, request):
self.list(request)
...
def post(self, request):
self.create(request)
...
2. 中間件
Django中的中間件是一個輕量級、底層的插件系統,可以介入Django的請求和響應處理過程,修改Django的輸入或輸出。中間件的設計為開發者提供了一種無侵入式的開發方式,增強了Django框架的健壯性。
我們可以使用中間件,在Django處理視圖的不同階段對輸入或輸出進行干預。
1. 中間件的定義方法
定義一個中間件工廠函數,然后返回一個可以被調用的中間件。
中間件工廠函數需要接收一個可以調用的get_response對象。
返回的中間件也是一個可以被調用的對象,并且像視圖一樣需要接收一個request對象參數,返回一個response對象。
def simple_middleware(get_response):
# 此處編寫的代碼僅在Django第一次配置和初始化的時候執行一次。
def middleware(request):
# 此處編寫的代碼會在每個請求處理視圖前被調用。
response = get_response(request)
# 此處編寫的代碼會在每個請求處理視圖之后被調用。
return response
return middleware
例如,在users應用中新建一個middleware.py文件,
def my_middleware(get_response):
print('init 被調用')
def middleware(request):
print('before request 被調用')
response = get_response(request)
print('after response 被調用')
return response
return middleware
定義好中間件后,需要在settings.py 文件中添加注冊中間件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'users.middleware.my_middleware', # 添加中間件
]
定義一個視圖進行測試
def demo_view(request):
print('view 視圖被調用')
return HttpResponse('OK')
執行結果:
注意:
- Django運行在調試模式下,中間件init部分有可能被調用兩次。
2. 執行流程
3. 多個中間件的執行順序
- 在請求視圖被處理前,中間件由上至下依次執行
- 在請求視圖被處理后,中間件由下至上依次執行
示例:
定義兩個中間件
def my_middleware(get_response):
print('init 被調用')
def middleware(request):
print('before request 被調用')
response = get_response(request)
print('after response 被調用')
return response
return middleware
def my_middleware2(get_response):
print('init2 被調用')
def middleware(request):
print('before request 2 被調用')
response = get_response(request)
print('after response 2 被調用')
return response
return middleware
注冊添加兩個中間件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'users.middleware.my_middleware', # 添加
'users.middleware.my_middleware2', # 添加
]
執行結果
init2 被調用
init 被調用
before request 被調用
before request 2 被調用
view 視圖被調用
after response 2 被調用
after response 被調用
6. 模板
1. Django自帶模板使用
1. 配置
在工程中創建模板目錄templates。
在settings.py配置文件中修改TEMPLATES配置項的DIRS值:
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',
],
},
},
]
2. 定義模板
在templates目錄中新建一個模板文件,如index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{ city }}</h1>
</body>
</html>
3. 模板渲染
Django提供了一個函數render實現模板渲染。
render(request對象, 模板文件路徑, 模板數據字典)
from django.shortcuts import render
def index(request):
context={'city': '北京'}
return render(request,'index.html',context)
2. 模板語法
1. 模板變量
變量名必須由字母、數字、下劃線(不能以下劃線開頭)和點組成。
語法如下:
{{變量}}
模板變量可以使python的內建類型,也可以是對象。
views.py文件:
def index(request):
context = {
'city': '北京',
'adict': {
'name': '西游記',
'author': '吳承恩'
},
'alist': [1, 2, 3, 4, 5]
}
return render(request, 'index.html', context)
html文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{ city }}</h1>
<h1>{{ adict }}</h1>
<h1>{{ adict.name }}</h1> 注意字典的取值方法
<h1>{{ alist }}</h1>
<h1>{{ alist.0 }}</h1> 注意列表的取值方法
</body>
</html>
2. 模板語句(基本語法)
(1)for循環:
{% for item in 列表 %}
循環邏輯
{{forloop.counter}}表示當前是第幾次循環,從1開始
{%empty%} 列表為空或不存在時執行此邏輯
{% endfor %}
(2)if條件:
{% if ... %}
邏輯1
{% elif ... %}
邏輯2
{% else %}
邏輯3
{% endif %}
比較運算符如下:
==
!=
<
>
<=
>=
布爾運算符如下:
and
or
not
注意:運算符左右兩側不能緊挨變量或常量,必須有空格。
{% if a == 1 %} # 正確
{% if a==1 %} # 錯誤
3. 過濾器
語法如下:
-
使用管道符號|來應用過濾器,用于進行計算、轉換操作,可以使用在變量、標簽中。
-
如果過濾器需要參數,則使用冒號:傳遞參數。
變量|過濾器:參數
列舉自帶過濾器幾個如下:
-
safe,禁用轉義,告訴模板這個變量是安全的,可以解釋執行
-
length,長度,返回字符串包含字符的個數,或列表、元組、字典的元素個數。
-
default,默認值,如果變量不存在時則返回默認值。
data|default:'默認值'
-
date,日期,用于對日期類型的值進行字符串格式化,常用的格式化字符如下:
-
Y表示年,格式為4位,y表示兩位的年。
-
m表示月,格式為01,02,12等。
-
d表示日, 格式為01,02等。
-
j表示日,格式為1,2等。
-
H表示時,24進制,h表示12進制的時。
-
i表示分,為0-59。
-
s表示秒,為0-59。
value|date:"Y年m月j日 H時i分s秒"
-
template提供的內置過濾器,不夠用,不靈活,就可以自己定義一個過濾器
-
1:在自己的app里建一個templatetags包,在包里創建一個后面要在HTML文件引用的py文件,
-
2:在py文件中,先導入from django import template ,
實例化對象register = template.Library()
創建一個template能認識的函數
對創建的每一個過濾器,都要用加上裝飾器
-
3:在HTML文件中引用
- load mytag
- 使用過濾器
注意點:
- templatetags文件夾 要在各自的應用內創建
4. 模板繼承
模板繼承和類的繼承含義是一樣的,主要是為了提高代碼重用,減輕開發人員的工作量。
父模板
如果發現在多個模板中某些內容相同,那就應該把這段內容定義到父模板中。
標簽block:用于在父模板中預留區域,留給子模板填充差異性的內容,名字不能相同。 為了更好的可讀性,建議給endblock標簽寫上名字,這個名字與對應的block名字相同。父模板中也可以使用上下文中傳遞過來的數據。
{% block 名稱 %}
預留區域,可以編寫默認內容,也可以沒有默認內容
{% endblock 名稱 %}
子模板
標簽extends:繼承,寫在子模板文件的第一行。
{% extends "父模板路徑"%}
子模版不用填充父模版中的所有預留區域,如果子模版沒有填充,則使用父模版定義的默認值。
填充父模板中指定名稱的預留區域。
{% block 名稱 %}
實際填充內容
{{ block.super }}用于獲取父模板中block的內容
{% endblock 名稱 %}
5. 注釋
(1)單行注釋
語法如下:
{#...#}
(2)多行注釋使用comment標簽
語法如下:
{% comment %}
...
{% endcomment %}
2. Django中使用jinja2模板
jinja2介紹
- Jinja2:是 Python 下一個被廣泛應用的模板引擎,是由Python實現的模板語言,他的設計思想來源于 Django 的模板引擎,并擴展了其語法和一系列強大的功能,尤其是Flask框架內置的模板語言
由于django默認模板引擎功能不齊全,速度慢,所以我們也可以在Django中使用jinja2, jinja2宣稱比django默認模板引擎快10-20倍。
Django主流的第三方APP基本上也都同時支持Django默認模板及jinja2,所以要用jinja2也不會有多少障礙。
1. 安裝jinja2模塊
pip install jinja2
2. Django配置jinja2
(1)在項目文件中創建 jinja2_env.py 文件
from jinja2 import Environment
def environment(**options):
env = Environment(**options)
return env
(2)在settings.py文件
TEMPLATES = [
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',#修改1
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS':True,
'OPTIONS':{
'environment': 'jinja2_env.environment',# 修改2
'context_processors':[
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
3. jinja2模板的使用絕大多數和Django自帶模板一樣
for循環有差異
4. jinja2自定義過濾器
在jinja2_env.py文件中自定義過濾器
from jinja2 import Environment
def environment(**options):
env = Environment(**options)
# 2.將自定義的過濾器添加到 環境中
env.filters['do_listreverse'] = do_listreverse
return env
# 1.自定義過濾器
def do_listreverse(li):
if li == "B":
return "哈哈"
3. CSRF
-
CSRF全拼為Cross Site Request Forgery,譯為跨站請求偽造。
-
CSRF指攻擊者盜用了你的身份,以你的名義發送惡意請求。
- 包括:以你名義發送郵件,發消息,盜取你的賬號,甚至于購買商品,虛擬貨幣轉賬…
-
造成的問題:個人隱私泄露以及財產安全。
1. CSRF攻擊示意圖
- 客戶端訪問服務器時沒有同服務器做安全驗證
2. 防止 CSRF 攻擊
步驟
-
在客戶端向后端請求界面數據的時候,后端會往響應中的 cookie 中設置 csrf_token 的值
-
在 Form 表單中添加一個隱藏的的字段,值也是 csrf_token
-
在用戶點擊提交的時候,會帶上這兩個值向后臺發起請求
-
后端接受到請求,以會以下幾件事件:
- 從 cookie中取出 csrf_token
- 從 表單數據中取出來隱藏的 csrf_token 的值
- 進行對比
-
如果比較之后兩值一樣,那么代表是正常的請求,如果沒取到或者比較不一樣,代表不是正常的請求,不執行下一步操作
3. CSRF_TOKEN的設置過程
如有不足,歡迎指正!
智能推薦
python web應用框架Django使用教程
本人python版本3.4 首先安裝Django 然后查看是否安裝成功 python -m django --version 出現版本即為成功。 然后創建項目 django-admin startproject mysite 結構如下: 外部mysite是目錄名,名字可以更改 manage.py一個可以和Django交互的程序 內部的mysite才是實際python包 mysite/__init_...
基于Django框架的python web
項目名稱:基于Django的python web 摘要 Django是一個開放源代碼的Web應用框架,由Python寫成。采用了MTV的框架模式,即模型M,視圖V和模版T。它最初是被開發來用于管理勞倫斯出版集團旗下的一些以新聞內容為主的網站的,即是CMS(內容管理系統)軟件。并于2005年7月在BSD許可證下發布。這套框架是以比利時的吉普賽爵士吉他手Django Reinhardt來命名的。201...
Python中Django框架開發web
采用idea工具進行開發: 1.Django的基本知識點: Django是Python語言中最具有代表性的一種開發web的框架; Django是一個開發源代碼的web應用框架,由Python寫成; Django采用MVC軟件設計模式,即:模型,視圖,控制器。 2.Django的優缺點: ①優點: a.Django自帶的ORM:每條記錄都是一個對象,更方便去對象的關聯,封裝性能好,開發速度快; b....
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
猜你喜歡
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...