Django框架全面講解二
七、中間件(MiddleWare)
django 中的中間件(middleware),在django中,中間件其實就是一個類,在請求到來和結束後,django會根據自己的規則在合適的時機執行中間件中相應的方法。
在django項目的settings模塊中,有一個 MIDDLEWARE_CLASSES 變量,其中每一個元素就是一箇中間件,如下圖
中間件中可以定義五個方法,分別是:
- process_request(self,request)
- process_view(self, request, callback, callback_args, callback_kwargs)
- process_template_response(self,request,response)
- process_exception(self, request, exception)
- process_response(self, request, response
分析源碼得知前二個方法是從前往後執行的,後三個方法是從後往前執行的
所以前兩個方法是請求進來的,後三個方法是請求出去的
一張圖告訴你中間件的運行流程
自定義中間件
1、創建中間件類
class Middle_Test(object):
def process_request(self,request):
pass
def process_view(self, request, callback, callback_args, callback_kwargs):
1
pass
def process_exception(self, request, exception):
pass
def process_response(self, request, response):
return response
2、註冊中間件
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'sparks.middleware.auth.Middle_Test',
)
八、 Form
1.使用 forms 模塊生成表單,主要處理GET請求
1.forms模塊的作用
通過forms模塊,允許將表單與class結合(表單與實體類結合),允許通過class生成表單
2.使用forms模塊
1.在應用中創建 forms.py 文件
2.導入forms模塊
from django import forms
3.創建class,一個class對應生成一個表單
class ClassName(forms.Form):
pass
4.創建屬性
一個屬性對應到表單中生成一個控件
3.在模板中解析 form 對象
1.注意
在模板中,需要:
1.自定義 <form></form>
2.自定義 提交按鈕
2.處理方法
1.在 views 中創建 form 的對象併發送到模板上
form = RemarkForm()
return render(request,'xxx.html',locals())
2.在模板中進行解析
1.手動解析
{% for field in form %}
{{field}} :
表示的就是form對象中的一個獨立屬性
表示的也就是一個獨立的控件
{{field.label}}:
表示的是控件中的label的值
{% endfor %}
2.自動解析
1.{{form.as_p}}
將form對象中的每個屬性使用p標記包裹起來再顯示
2.{{form.as_ul}}
將form對象中的每個屬性使用li標記包裹起來,再顯示
注意:必須手動提供<ol> 或 <ul>
3.{{form.as_table}}
將form對象中的每個屬性用tr標記包裹起來,再顯示
注意:必須手動提供<table>
2.通過 forms.Form 獲取表單數據 - POST
1.通過 forms.Form 的構造函數來接收post數據
form = RemarkForm(request.POST)
2.必須使form通過驗證後再獲取數據
form.is_valid()
返回True:提交的數據以及表單已通過所有的驗證,允許取值
返回False:未通過驗證,則不能正常取值
3.獲取表單中的數據
通過 form.cleaned_data 來獲取提交的數據
from django import forms
#聲明ChoiceField要用到的數據
TOPIC_CHOICE = (
('1', '好評'),
('2', '中評'),
('3', '差評'),
)
class RemarkForm(forms.Form):
#評論標題
# forms.CharField() - 文本框
# label : 控件前的文本標籤
subject = forms.CharField(label='標題')
#電子郵箱
# forms.EmailField() - Email框
# label : 控件前的文本標籤
email = forms.EmailField(label='郵箱')
#品論內容
# widget=Textarea : 將當前的單行文本框變爲多行文本域
message = forms.CharField(label='內容', widget=forms.Textarea)
#品論級別
# forms.ChoiceField() - 下拉列表框
# choices : 表示當前下拉列表框中的數據,取值爲元組或列表
topic = forms.ChoiceField(label='級別', choices=TOPIC_CHOICE)
#是否保存-複選框
isSaved = forms.BooleanField(label='是否保存')
def form_register(request):
if request.method == 'GET':
form = RegisterForm()
return render(request,'07-form-register.html',locals())
else:
# 將request.POST中的數據提交給RegisterForm()
form = RegisterForm(request.POST)
# 將數據通過驗證
if form.is_valid():
# 驗證過後獲取數據並保存進數據庫
au = Author(**form.cleaned_data)
au.save()
return HttpResponse("Register OK")
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#id_subject{
border:none;
border-bottom:1px solid #000;
outline:none;
}
</style>
</head>
<body>
{% comment '手動解析' %}
<form action="/06-form/" method="post">
{% csrf_token %}
{% for field in form %}
<p>
{{ field.label }}:{{ field }}
</p>
{% endfor %}
<p>
<input type="submit">
</p>
</form>
{% endcomment %}
{% comment '自動解析- {{ form.as_p }}' %}
<form action="/06-form/" method="post">
{{ form.as_p }}
<p>
<input type="submit">
</p>
</form>
{% endcomment %}
</body>
1.使用 forms 模塊
2.forms模塊的高級處理
將 Models 和 Forms 結合到一起使用
1.在 forms.py 中創建 class ,繼承自 forms.ModelForm
2.創建內部類Meta,去關聯 Model
1.model : 指定要關聯的實體類
2.fields : 指定從Model中取哪些字段生成控件
1.取值 "__all__",表示全部屬性都要生成控件
2.取值 列表,聲明允許生成控件的屬性名
3.labels : 指定每個屬性所關聯的label,取值爲字典
labels = {
'屬性名':'label文本',
'屬性名':'label文本',
}
3.內置小部件 - widget
1.什麼是小部件
小部件,表示的就是生成到網頁上的控件類型以及其他的html屬性
2.常用小部件類型
1.TextInput : type='text'
2.PasswordInput : type='password'
3.NumberInput : type='number'
4.EmailInput : type='email'
5.URLInput : type='url'
6.HiddenInput : type='hidden'
7.CheckboxInput : type='checkbox'
8.Textarea : <textarea></textarea>
9.Select : <select></select>
3.小部件的使用
1.繼承自 forms.Form 類
1.基本版
只指定控件的類型
class RemarkForm(forms.Form):
屬性 = forms.CharField(
label='文本',
widget=forms.小部件類型
)
2.高級版
指定控件類型的基礎上還允許設置一些相關的HTML屬性到控件上
屬性 = forms.CharField(
label = '文本',
widget = forms.小部件類型(
attrs = {
'html屬性名':'屬性值',
'html屬性名':'屬性值',
}
)
)
2.繼承自 forms.ModelForm 類
class XXXForm(forms.ModelForm):
class Meta:
model = xxxx
fields = "__all__" 或 []
labels = {
'屬性1':'標籤1',
}
#指定小部件
widgets = {
"屬性1":forms.小部件類型(
attrs = {
'屬性':'值',
}
),
}
class WidgetForm2(forms.ModelForm):
class Meta:
#指定關聯的實體
model = Author
#指定要顯示的字段
fields = ['name','age','email']
#指定字段對應的標籤
labels = {
'name':'用戶姓名',
'age':'用戶年齡',
'email':'用戶郵箱',
}
#指定字段對應的小部件
widgets = {
'age':forms.NumberInput(
attrs = {
'placeholder':'請輸入年齡',
'class':'form-control',
}
),
'email':forms.EmailInput(
attrs = {
'placeholder':'請輸入您的電子郵箱',
'class':'form-control',
}
)
}
def widget2_views(request):
if request.method == 'GET':
form = WidgetForm2()
return render(request,'08-widget1.html',locals())
else:
# 將request.POST中的數據提交給RegisterForm()
form = RegisterForm(request.POST)
# 將數據通過驗證
if form.is_valid():
# 驗證過後獲取數據並保存進數據庫
au = Author(**form.cleaned_data)
au.save()
return HttpResponse("Register OK")
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
input.form-control{
border:1px solid #000;
width:300px;
height:30px;
box-sizing:border-box;
padding:3px 10px;
outline:none;
}
</style>
</head>
<body>
<form action="/09-widget2">
{{ form.as_p }}
</form>
</body>
</html>
九、 認證系統(auth)
auth模塊是Django提供的標準權限管理系統,可以提供用戶身份認證, 用戶組管理,並且可以和admin模塊配合使用.
在INSTALLED_APPS中添加’django.contrib.auth’使用該APP, auth模塊默認啓用.
新建用戶
from django.contrib.auth.models import User
user = User.objects.create_user(username, email, password)
user.save()
# 不存儲用戶密碼明文而是存儲一個Hash值
認證用戶
from django.contrib.auth import authenticate
user = authenticate(username=username, password=password)
# 認證用戶的密碼是否有效, 若有效則返回代表該用戶的user對象, 若無效則返回None.
# 該方法不檢查is_active標誌位.
修改密碼:
user.set_password(new_password)
# 以下實例爲先認證通過後纔可以修改密碼
user = auth.authenticate(username=username, password=old_password)
if user is not None:
user.set_password(new_password)
user.save()
登錄
from django.contrib.auth import login
# login向session中添加SESSION_KEY, 便於對用戶進行跟蹤:
'login(request, user)'
# login不進行認證,也不檢查is_active標誌位
# 實例
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
退出登錄
# logout會移除request中的user信息, 並刷新session
from django.contrib.auth import logout
def logout_view(request):
logout(request)
只允許登錄的用戶訪問
@login_required裝飾器裝飾的view函數會先通過session key檢查是否登錄, 已登錄用戶可以正常的執行操作, 未登錄用戶將被重定向到login_url指定的位置,若未指定login_url參數, 則重定向到settings.LOGIN_URL
from django.contrib.auth.decorators import login_required
@login_required(login_url='/accounts/login/')
def userinfo(request):
...
# settings 配置
LOGIN_URL = '/index/'
# views
@login_required
def userinfo(request):
...
十、 跨站請求僞造(csrf)
django爲用戶實現防止跨站請求僞造的功能,通過中間件 django.middleware.csrf.CsrfViewMiddleware 來完成。而對於django中設置防跨站請求僞造功能有分爲全局和局部。
全局:
中間件 django.middleware.csrf.CsrfViewMiddleware
局部:
- @csrf_protect,爲當前函數強制設置防跨站請求僞造功能,即便settings中沒有設置全局中間件。
- @csrf_exempt,取消當前函數防跨站請求僞造功能,即便settings中設置了全局中間件。
注:from django.views.decorators.csrf import csrf_exempt,csrf_protec
應用
1、普通表單
# veiw中設置返回值:
return render(request, 'xxx.html', data)
# html中設置Token:
{% csrf_token %}
十一、2.cookies 和 session
2.cookies 和 session
1.cookies
1.django 中使用 cookies
1.設置cookies的值(將數據保存到客戶端)
語法:
響應對象.set_cookie(key,value,expires)
key:cookie的名字
value:cookie的值
expires:保存時間,以s爲單位
1.不使用模板
resp = HttpResponse('響應給客戶端的一句話')
resp.set_cookie(key,value,expires)
return resp
2.使用模板
resp = render(request,'xxx.html',locals())
resp.set_cookie(key,value,expires)
return resp
3.使用重定向
resp = redirect('/地址/')
resp.set_cookie(key,value,expires)
return resp
2.獲取cookies的值
伴隨着請求對象到達服務器之後再獲取cookie的值
request.COOKIES:封裝了當前訪問站點下的所有的cookie的信息
3.刪除cookie的值
通過響應對象通知客戶端刪除數據
resp.delete_cookie(key)
2.session
1.設置 session 的值
request.session['key'] = 值
2.獲取 session 的值
value = request.session['key']
value = request.session.get('key')
3.刪除 session 的值
del request.session['key']
4.有關 session 的配置
在 settings.py 中,有關session的設置
1.SESSION_COOKIE_AGE
作用:設置sessionID在cookies中的存活時間
ex:
SESSION_COOKIE_AGE=60*30
2.SESSION_EXPIRE_AT_BROWSER_CLOSE
作用:設置瀏覽器關閉時則清除服務器上對應的session空間
ex:
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
十二、Session
Django中默認支持Session,其內部提供了5種類型的Session供開發者使用:
- 數據庫(默認)
- 緩存
- 文件
- 緩存+數據庫
- 加密cookie
1.數據庫Session
Django默認支持Session,並且默認是將Session數據存儲在數據庫中,即:django_session 表中。
a. 配置 settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默認)
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上 時的key,即:sessionid=隨機字符串(默認)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑(默認)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默認)
SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie(默認)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸(默認)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默認)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過期(默認)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都保存Session,默認修改之後才保存(默認)
b. 使用
def index(request):
# 獲取、設置、刪除Session中數據
request.session['k1']
request.session.get('k1',None)
request.session['k1'] = 123
request.session.setdefault('k1',123) # 存在則不設置
del request.session['k1']
# 所有 鍵、值、鍵值對
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()
# 用戶session的隨機字符串
request.session.session_key
# 將所有Session失效日期小於當前日期的數據刪除
request.session.clear_expired()
# 檢查 用戶session的隨機字符串 在數據庫中是否
request.session.exists("session_key")
# 刪除當前用戶的所有Session數據
request.session.delete("session_key")
...
2、緩存Session
a. 配置 settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎
SESSION_CACHE_ALIAS = 'default' # 使用的緩存別名(默認內存緩存,也可以是memcache),此處別名依賴緩存的設置
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名
SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過期
SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都保存Session,默認修改之後才保存
b. 使用
同上
3、文件Session
a. 配置 settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎
SESSION_FILE_PATH = None # 緩存文件路徑,如果爲None,則使用tempfile模塊獲取一個臨時地址tempfile.gettempdir() # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路徑
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名
SESSION_COOKIE_SECURE = False # 是否Https傳輸cookie
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http傳輸
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過期
SESSION_SAVE_EVERY_REQUEST = False # 是否每次請求都保存Session,默認修改之後才保存
b. 使用
同上
4、緩存 + 數據庫 Session
數據庫用於做持久化,緩存用於提高效率
a. 配置 settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎
b. 使用
同上
5、加密cookie Session
a. 配置 settings.py
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
b. 使用
同上
十三、緩存
由於Django是動態網站,所有每次請求均會去數據進行相應的操作,當程序訪問量大時,耗時必然會更加明顯,最簡單解決方式是使用:緩存,緩存將一個某個views的返回值保存至內存或者memcache中,5分鐘內再有人來訪問時,則不再去執行view中的操作,而是直接從內存或者Redis中之前緩存的內容拿到,並返回。
Django中提供了6種緩存方式:
- 開發調試
- 內存
- 文件
- 數據庫
- Memcache緩存(python-memcached模塊)
- Memcache緩存(pylibmc模塊)
和數據庫類似,緩存的具體操作都是一樣的,使用不同的方式只需要將配置改掉即可
1、配置
a、開發調試
# 此爲開始調試用,實際內部不做任何操作
# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎
'TIMEOUT': 300, # 緩存超時時間(默認300,None表示永不過期,0表示立即過期)
'OPTIONS':{
'MAX_ENTRIES': 300, # 最大緩存個數(默認300)
'CULL_FREQUENCY': 3, # 緩存到達最大個數之後,剔除緩存個數的比例,即:1/CULL_FREQUENCY(默認3)
},
'KEY_PREFIX': '', # 緩存key的前綴(默認空)
'VERSION': 1, # 緩存key的版本(默認1)
'KEY_FUNCTION' 函數名 # 生成key的函數(默認函數會生成爲:【前綴:版本:key】)
}
}
# 自定義key
def default_key_func(key, key_prefix, version):
"""
Default function to generate keys.
Constructs the key used by all other methods. By default it prepends
the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
function with custom key making behavior.
"""
return '%s:%s:%s' % (key_prefix, version, key)
def get_key_func(key_func):
"""
Function to decide which key function to use.
Defaults to ``default_key_func``.
"""
if key_func is not None:
if callable(key_func):
return key_func
else:
return import_string(key_func)
return default_key_func
b、內存
# 此緩存將內容保存至內存的變量中
# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake',
}
}
# 注:其他配置同開發調試版本
c、文件
# 此緩存將內容保存至文件
# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache',
}
}
# 注:其他配置同開發調試版本
d、數據庫
# 此緩存將內容保存至數據庫
# 配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table', # 數據庫表
}
}
# 注:執行創建表命令 python manage.py createcachetable
e、Memcache緩存(python-memcached模塊)
# 此緩存使用python-memcached模塊連接memcache
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': 'unix:/tmp/memcached.sock',
}
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
}
}
f、Memcache緩存(pylibmc模塊)
# 此緩存使用pylibmc模塊連接memcache
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '127.0.0.1:11211',
}
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '/tmp/memcached.sock',
}
}
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
}
}
2、應用
a. 全站使用
使用中間件,經過一系列的認證等操作,如果內容在緩存中存在,則使用FetchFromCacheMiddleware獲取內容並返回給用戶,當返回給用戶之前,判斷緩存中是否已經存在,如果不存在則UpdateCacheMiddleware會將緩存保存至緩存,從而實現全站緩存
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
# 其他中間件...
'django.middleware.cache.FetchFromCacheMiddleware',
]
CACHE_MIDDLEWARE_ALIAS = ""
CACHE_MIDDLEWARE_SECONDS = ""
CACHE_MIDDLEWARE_KEY_PREFIX = ""
b. 單獨視圖緩存
方式一:
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def my_view(request):
...
方式二:
from django.views.decorators.cache import cache_page
urlpatterns = [
url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
]
c、局部視圖使用
a. 引入TemplateTag
{% load cache %}
b. 使用緩存
{% cache 5000 緩存key %}
緩存內容
{% endcache %}
注:如果出現多個url匹配同一個view函數的情況,緩存機制會根據每一個不同的url做單獨的緩存