前臺發送URL請求到Django的中間件進行內容校驗,完成校驗後到達路由映射文件url.py,而後調用視圖函數views.py裏面的函數進行內容處理【 1.操做數據庫進行數據讀寫 2. 調用前臺的模版內容】最後返回字符串給前臺進行頁面的渲染【這裏回去的時候也會通過中間件】。 css
【更多參考】http://www.cnblogs.com/wupeiqi/articles/5246483.html html
Django中間件相似於Java框架中的攔截器之類的東西,就是在請求到達咱們要操做的函數以前添加的一些判斷之類的操做。 python
應用場景: 適用於全局的操做,對全部的用戶請求/用戶返回數據都須要處理的狀況。process_request適用於請求到達以前已經執行的操做,相似防禦的操做[例如,csrf中間件,過濾器,自定義請求頭]; jquery
Django中間件即類中的方法執行順序是Django固定的,不能更改執行順序,函數名稱也不能更改【若是自定義了MiddlewareMixin的話,能夠不使用固定的名稱】 ajax
注:這裏的函數是不須要所有寫的,也就是process_request和process_response無關緊要 sql
中間件中能夠定義四個方法,分別是:數據庫
process_request(self,request)django
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)
中間件實例
建立中間件路徑【文件夾+文件】
settings.py
INSTALLED_APPS = [ ... 'app01', # 註冊app ] STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 現添加的配置,這裏是元組,注意逗號 TEMPLATES = [ ... 'DIRS': [os.path.join(BASE_DIR, 'templates')], ] MIDDLEWARE = [ ... # 'django.middleware.csrf.CsrfViewMiddleware', 'plugin.handler.Handler', 'plugin.handler.Handler2', 'plugin.handler.Handler3', ]
urls.py
from django.contrib import admin from django.urls import path from django.conf.urls import url, include from app01 import views urlpatterns = [ url('test/', views.Test), url('test/(\d+)/', views.Test1), # url('test/(?P<nid>\d{3})/', views.Test2), # 效果同Test1,只不過nid的名稱是固定,kv形式返回 ]
views.py
from django.shortcuts import render, redirect, HttpResponse from app01 import models # 中間層操做 class Foo: def __init__(self, request, html): self.req = request self.html = html def render(self): return render(self.req, self.html) def Test(request): print('views') return HttpResponse("OK") def Test1(request,nid): print('views1') return HttpResponse("OK1") def Test2(request, nid): print('views2') return HttpResponse("OK2") # 測試process_template_response,這裏不作細節演示 def Test4(request, nid): print('views2') return Foo(request, 'test.html')
plugin/handler.py
# version: python3.2.5 # 中間件測試 # 新的中間件【複製的原類,爲了規範起見,全部中間件繼承於此】 # 另:繼承了自定義的MiddlewareClass就能夠自定義函數名了,不必定是process_request class MiddlewareClass(object): def __init__(self, get_response=None): self.get_response = get_response super(MiddlewareClass, self).__init__() def __call__(self, request): response = None if hasattr(self, 'process_request'): # 執行當前中間件的process_request response = self.process_request(request) if not response: # 執行下一個中間件的__call__()方法 response = self.get_response(request) if hasattr(self, 'process_response'): # 執行當前中間件的process_response response = self.process_response(request, response) return response from django.utils.deprecation import MiddlewareMixin # 原始的繼承類 from django.shortcuts import HttpResponse class Handler(MiddlewareClass): def process_request(self, request): print('A --> process_request') # return HttpResponse("Handler的process_response結束了請求...") #Django2.0.1中此方法會終止後面的中間件請求 # 根據url.py裏面的路由映射獲取views.py裏面的函數,函數參數 # view_func: 函數名 # view_args:參數名 # view_kwargs: 若是參數名指定了列名,則key-value形式顯示 # 執行的時候會按照A->B->C的順序依次執行中間件內容,完成後去執行process_exception def process_view(self, request, view_func, view_args, view_kwargs): print('A --> process_view') # 這個函數只對views.py裏面的報錯進行處理,其餘異常均不處理 # 異常處理完成後返回到最後一箇中間件process_response進行response處理 def process_exception(self, request, exception): print('A --> process_exception') def process_response(self, request, response): print('A --> process_response') return response # views.py函數若是返回的是HttpResponse("OK1"),則這個函數並不作什麼操做 # views.py函數若是返回的是Render(request, 'index.html'),則這個函數也不作什麼操做 # views.py函數若是返回的對象new Obj()有Render方法,則這個函數會去render函數裏面作操做 def process_template_response(self, request, response): print('A --> process_template_response') return response class Handler2(MiddlewareClass): def process_request(self, request): print('B --> process_request') def process_view(self, request, view_func, view_args, view_kwargs): print('B --> process_view') print('view_func:', view_func) print('view_args:', view_args) print('view_kwargs:', view_kwargs) def process_exception(self, request, exception): print('B --> process_exception') def process_response(self, request, response): print('B --> process_response') print("Response類型:", response) print("Response類型:", type(response)) return response def process_template_response(self, request, response): print('B --> process_template_response') return response class Handler3(MiddlewareClass): def process_request(self, request): print('C --> process_request') def process_view(self, request, view_func, view_args, view_kwargs): print('C --> process_view') def process_exception(self, request, exception): print('C --> process_exception') def process_response(self, request, response): print('C --> process_response') return response def process_template_response(self, request, response): print('C --> process_template_response') return response
templates/XXX.html
無
頁面顯示;
正常訪問執行順序:
中間件request請求中返回response效果:
另外其餘的函數執行效果:
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_protect
settings.py裏面若是未註釋掉CSRF驗證【即須要CSRF驗證】
咱們的get請求能夠經過,post請求會被攔截
Django裏面使用form的post請求發送數據的時候,必定是return了一個render對象,且HTML的form表單內使用了{% csrf_token %}進行標記,此時前臺的HTML裏面會多出一行csrf的token同時會緩存一份到Cookie裏面。同理,若是咱們須要ajax發送post請求的時候,是須要從Cookie裏面獲取token[從截圖能夠看到Cookie裏面token的key是csrftoken]並添加到請求頭[request-header]裏讓Django進行驗證的。
Ajax請求CSRF實例
settings.py
INSTALLED_APPS = [ ... 'app01', # 註冊app ] MIDDLEWARE = [ ... 'django.middleware.csrf.CsrfViewMiddleware', ... ] STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 現添加的配置,這裏是元組,注意逗號 TEMPLATES = [ ... 'DIRS': [os.path.join(BASE_DIR, 'templates')], ]
urls.py
from django.contrib import admin from django.urls import path from django.conf.urls import url, include from app01 import views urlpatterns = [ url('login/', views.Login), ]
views.py
from django.shortcuts import render, redirect, HttpResponse from app01 import models # SCRF測試 def Login(request): # 注意這裏的settings是Django默認的 # 咱們看到的寫入的settings.py文件會讀入並覆蓋conf裏面的setting from django.conf import settings print('settings.CSRF_HEADER_NAME: ', settings.CSRF_HEADER_NAME) print(request.method) return render(request, 'login.html')
templates/login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> <form action="/login/" method="post"> {% csrf_token %} 姓名:<input type="text" name="username"> <input type="submit" value="Form提交"> <input type="button" value="Ajax提交" id="btn"> </form> </body> <script src="/static/jquery-2.1.4.min.js"></script> <script src="/static/JQuery.Cookies.js"></script> <script> $(function () { {# 這裏對請求頭作統一的處理,發送請求以前進行批量的配置 #} $.ajaxSetup({ beforeSend: function(xhr) { xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken')); } }); $("#btn").click(function () { $.ajax({ url: '/login/', type:'POST', {# headers: {'X-CSRFTOKEN': 'hhh'},#} {# headers: {'X-CSRFTOKEN': $.cookie('csrftoken')}, 這裏是自定義添加token#} data: {username: 'root'}, success: function (args) { console.log(args) } }) }) }) </script> </html>
PS: 獲取request裏面的請求信息,可使用斷點打印,咱們能夠看出咱們request裏的header通過Django處理後在Meta裏面呢,且字段名前添加了HTTP的前綴。
頁面顯示;
其餘
【更多參考】http://www.cnblogs.com/wupeiqi/articles/5246483.html
因爲Django是動態網站,全部每次請求均會去數據進行相應的操做,當程序訪問量大時,耗時必然會更加明顯,最簡單解決方式是使用:緩存,緩存將一個某個views的返回值保存至內存或者memcache中,5分鐘內再有人來訪問時,則再也不去執行view中的操做,而是直接從內存或者Redis中以前緩存的內容拿到,並返回。
緩存適用於固定內容且訪問量大,大型文件內容,不具備實時性的內容。
Django中提供了6種緩存方式:
開發調試 --> 什麼都不幹
內存
文件
數據庫
Memcache緩存(python-memcached模塊) -->在另一臺服務器上
Memcache緩存(pylibmc模塊)
配置:
開發調試
# 此爲開始調試用,實際內部不作任何操做 # 配置: 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】) } } 注:memache幫咱們生成key的時候,會之前綴+版本+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
內存:
# 此緩存將內容保存至內存的變量中 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'unique-snowflake',# 此參數就是標誌惟一變量名稱用於指引value可任意指定 } } # 注:其餘配置同開發調試版本
文件:
# 此緩存將內容保存至文件 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': '/var/tmp/django_cache', # 指定文件路徑,文件存放位置 } } # 注:其餘配置同開發調試版本
數據庫:
# 此緩存將內容保存至數據庫 # 配置: CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', 'LOCATION': 'my_cache_table', # 指定數據庫表,一條數據就是一個緩存 } } # 注:執行建立表命令 python manage.py createcachetable -->專門防止緩存的表
Memcache緩存(python-memcached模塊)
Memcache能夠理解爲另一個服務器的內存,是內存級別的緩存;
內容以Key-Value形式存儲,總體的Memcache就是一個大字典
# 此緩存使用python-memcached模塊鏈接memcache # 3種鏈接方式 CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 'LOCATION': '127.0.0.1:11211', # 根據IP和端口鏈接指定機器 } } # 此方法只能鏈接本機信息 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', 10), # 鏈接多個服務器,相似分佈式哈~ ('172.19.26.242:11211', 15), # 數據存儲再多個服務器上... ('172.19.26.241:11211,’ 20), # 設置了權重的鏈接,用戶輸入的key會計算hash值,返回一個int數字,後根據取餘求算存儲位置,根據權重肯定服務器。加了權重後的,此時至關於10+15+20個服務器了,寫入第三個服務器[有20個]的機率大 ] } }
Memcache緩存(pylibmc模塊)
# 此緩存使用pylibmc模塊鏈接memcache # 共3種鏈接方式 # 解釋同上 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', ] } }
注:memache中若是有服務器故障,由於memacahe裏面沒有檢測機制,只能本身監控該模塊,更改模塊裏面的接口方法處理
Django中提供了3種緩存方式:
全棧使用緩存
單獨視圖緩存
局部視圖使用
A. 全棧使用的配置
settings.py
MIDDLEWARE = [ 'django.middleware.cache.UpdateCacheMiddleware', # 其餘中間件... 'django.middleware.cache.FetchFromCacheMiddleware', ] CACHE_MIDDLEWARE_ALIAS = "" CACHE_MIDDLEWARE_SECONDS = "" CACHE_MIDDLEWARE_KEY_PREFIX = ""
B.單獨視圖緩存
settings.py
方式一: 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.局部視圖緩存
Html文件內寫
a. 引入TemplateTag {% load cache %} b. 使用緩存 {% cache 5000 緩存key %} 緩存內容 {% endcache %}
單獨視圖和局部視圖實例
settings.py
INSTALLED_APPS = [ ... 'app01', # 註冊app ] MIDDLEWARE = [ ... # 'django.middleware.csrf.CsrfViewMiddleware', ... ] STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 現添加的配置,這裏是元組,注意逗號 TEMPLATES = [ ... 'DIRS': [os.path.join(BASE_DIR, 'templates')], ] CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': os.path.join(BASE_DIR, 'cache'), # 指定文件路徑,文件存放位置 } }
urls.py
from django.contrib import admin from django.urls import path from django.conf.urls import url, include from app01 import views urlpatterns = [ url('cache/', views.Cache), url('part/', views.Cache_part), ]
views.py
from django.shortcuts import render, redirect, HttpResponse from app01 import models # 文件緩存之單獨視圖[views]緩存 -->緩存整個頁面及內容 from django.views.decorators.cache import cache_page @cache_page(10) def Cache(request): import time v = time.time() return HttpResponse(v) # 文件緩存之局部視圖緩存 -->緩存部分頁面內容 def Cache_part(request): import time v = time.time() return render(request, 'part.html', {'v':v})
templates/part.html
{% load cache %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body> <h1>H1:{{ v }}</h1> {% cache 10 time %} <h5>H5: {{ v }}</h5> {% endcache %} </body> </html>
頁面顯示;
文件緩存之單獨視圖緩存 :
文件緩存之局部視圖緩存 :
全棧使用實例
settings.py
INSTALLED_APPS = [ ... 'app01', # 註冊app ] MIDDLEWARE = [ 'django.middleware.cache.UpdateCacheMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.cache.FetchFromCacheMiddleware', ] STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 現添加的配置,這裏是元組,注意逗號 TEMPLATES = [ ... 'DIRS': [os.path.join(BASE_DIR, 'templates')], ] CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': os.path.join(BASE_DIR, 'cache'), # 指定文件路徑,文件存放位置 } }
其他同部分的單獨的使用...
頁面顯示;
全棧中間件代碼分析:
from django.middleware.cache import FetchFromCacheMiddleware
from django.middleware.cache import UpdateCacheMiddleware
bootStrap 一個集成css,js的文件
【bootStrap參考】 http://v3.bootcss.com/getting-started/