Django之缓存和信号
緩存
中間件和緩存之間的關系
在寫緩存之前寫了一個下中間件隨筆。是因為一般緩存頁面時,需要在respones用戶之前緩存到緩存服務器,因為如果在views處理后即存入緩存,可能會與用戶收到的頁面不一致,為什么呢?因為中間件有很多層,你不確定哪一層會對頁面做其他處理(包括頁面渲染,數據處理等等).
由于Django是動態網站,所有每次請求均會去數據進行相應的操作,當程序訪問量大時,耗時必然會更加明顯,最簡單解決方式是使用:緩存,緩存將一個某個views的返回值保存至內存或者memcache中,5分鐘內再有人來訪問時,則不再去執行view中的操作,而是直接從內存或者Redis中之前緩存的內容拿到,并返回。
Django提供的6中緩存機制
- 開發調試
- 內存
- 文件
- 數據庫
- Memcache緩存(python-memcached模塊
- Memcache緩存(pylibmc模塊,只是與上面換了個模塊而已)
配置
下面緩存的配置都在setting.py的文件中配置
開發調試
# 此為開始調試用,實際內部不做任何操作 # 配置: 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 prependsthe `key_prefix'. KEY_FUNCTION can be used to specify an alternatefunction 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_funcelse:return import_string(key_func)return default_key_func 開發調試?
內存模式
此緩存將內容保存至內存的變量中# 配置:CACHES = {'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache','LOCATION': 'unique-snowflake',}}# 注:其他配置同開發調試版本 內存模式?
?文件模式
# 此緩存將內容保存至文件# 配置: 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模塊)
# 此緩存使用python-memcached模塊連接memcache #單臺IP端口連接模式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',]}} Memcache緩存(python-memcached模塊)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',]}} Memcache緩存(pylibmc模塊)?
?緩存的應用
單獨視圖緩存
# 方式一、views.py中 from django.views.decorators.cache import cache_page @cache_page(60 * 15) # 相當于15分鐘 可以寫10這個相當于十秒 def cache(request):... # 方式二、urls.py中 from django.conf.urls import url from app01 import views from django.views.decorators.cache import cache_pageurlpatterns = [url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(views.cache)), # 和上面的同理 ]?
局部視圖使用
a. 引入TemplateTag{% load cache %}b. 使用緩存{% cache 5000 緩存key %}緩存內容{% endcache %}?
全站使用?
?在setting配置的加上2個中間件,'django.middleware.cache.UpdateMiddleware'這個中間件在最上面,'django.middleware.cache.FetchFormCacheMiddleware',這個中間件在最下面
?
然后你需要在項目配置文件中加入下面幾個必須的設置:
- CACHE_MIDDLEWARE_ALIAS:用來存儲的緩存別名
- CACHE_MIDDLEWARE_SECONDS:每個頁面應該被緩存的秒數? ?
- CACHE_MIDDLEWARE_KEY_PREFIX:關鍵的前綴,當多個站點使用同一個配置的時候,這個可以設置可以避免發生沖突;如果你不在乎的話, 你可以是用一個空字符串,建議你別這樣做
?'django.middleware.cache.UpdateMiddleware',
這個中間件的作用就是當服務器響應response是,它會查看這個響應是否有緩存,如果沒有就寫入到緩存中并返回給客戶端,否則直接返回給客戶端
'django.middleware.cache.FetchFormCacheMiddleware',
客戶端請求request時作用 查看是否有緩存,如果有不經過views直接返回,否則進入views視圖執行函數獲取緩存?
單獨視圖緩存示例:
setting的設置為文件保存緩存
CACHES = {'default': {'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache','LOCATION': os.path.join(BASE_DIR,'cache'),} }?
urls.py的代碼
# 第一種在試圖函數加裝飾器 from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [url(r'^admin/', admin.site.urls),url(r'^cache/$', views.cache), ]# 第二種方式在路由系統加裝飾器 from django.conf.urls import url from django.contrib import admin from app01 import views from django.views.decorators.cache import cache_page urlpatterns = [url(r'^admin/', admin.site.urls),url(r'^cache/$', cache_page(10)(views.cache)), # 緩存超時時間為10秒 ]?
views.py代碼
from django.views.decorators.cache import cache_page @cache_page(10) # 第二種方式就不需要在這家裝飾器 def cache(request):import timectime = time.time()return render(request, 'cache.html', {'ctime': ctime})?
cache.html代碼
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title></title> </head> <body><h1>{{ ctime }}</h1><h1>{{ ctime }}</h1><h1>{{ ctime }}</h1> </body> </html>?
局部視圖?
?setting部門代碼不變,
urls.py的代碼
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [url(r'^admin/', admin.site.urls),url(r'^cache/$', views.cache), ]?
views.py代碼
def cache(request):import timectime = time.time()return render(request, 'cache.html', {'ctime': ctime})?
cache.html代碼
{% load cache %} <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title></title> </head> <body><h1>{{ ctime }}</h1><h1>{{ ctime }}</h1>{% cache 10 c1 %}<h1>{{ ctime }}</h1> {# 只緩存該部分時間為十秒 #}{% endcache %} </body> </html>
Django緩存的三種方式的優先級,全站>單獨視圖>局部視圖
也就是說三種都寫了一最高優先級為準
信號
Django中提供了“信號調度”,用于在框架執行操作時解耦。通俗來講,就是一些動作發生的時候,信號允許特定的發送者去提醒一些接受者。我們可以使用這些功能來做一些日志記錄等等操作。
內置信號
Model signalspre_init # django的modal執行其構造方法前,自動觸發post_init # django的modal執行其構造方法后,自動觸發pre_save # django的modal對象保存前,自動觸發post_save # django的modal對象保存后,自動觸發pre_delete # django的modal對象刪除前,自動觸發post_delete # django的modal對象刪除后,自動觸發m2m_changed # django的modal中使用m2m字段操作第三張表(add,remove,clear)前后,自動觸發class_prepared # 程序啟動時,檢測已注冊的app中modal類,對于每一個類,自動觸發 Management signalspre_migrate # 執行migrate命令前,自動觸發post_migrate # 執行migrate命令后,自動觸發 Request/response signalsrequest_started # 請求到來前,自動觸發request_finished # 請求結束后,自動觸發got_request_exception # 請求異常后,自動觸發 Test signalssetting_changed # 使用test測試修改配置文件時,自動觸發template_rendered # 使用test測試渲染模板時,自動觸發 Database Wrappersconnection_created # 創建數據庫連接時,自動觸發 View Code因為這些信號中并沒有注冊函數,所以運行時并沒有調用觸發這些信號
對于Django內置的信號,僅需注冊指定信號,當程序執行相應操作時,自動觸發注冊函數:
from django.core.signals import request_finishedfrom django.core.signals import request_startedfrom django.core.signals import got_request_exceptionfrom django.db.models.signals import class_preparedfrom django.db.models.signals import pre_init, post_initfrom django.db.models.signals import pre_save, post_savefrom django.db.models.signals import pre_delete, post_deletefrom django.db.models.signals import m2m_changedfrom django.db.models.signals import pre_migrate, post_migratefrom django.test.signals import setting_changedfrom django.test.signals import template_renderedfrom django.db.backends.signals import connection_createddef callback(sender, **kwargs):print("xxoo_callback")print(sender,kwargs)xxoo.connect(callback) # 把上面的函數注冊到信號里 View Code?
這里的xxoo代指上面導入的信號,如request_finished,request_started,request_started等替換前面的xxoo,而callback就是你要注冊的函數
如果我們把導入信號以及將注冊函數都寫到一個單獨的文件里,為了在程序啟動的時候執行信號中的注冊函數,可以在于項目同名的文件中的init文件中導入該文件即可
自定義信號
自定義信號一共需要三步驟:
- 定義信號
- 注冊信號
- 觸發信號
自定義信號
import django.dispatch pizza_done=django.dispatch.Signal(providing_args=["toppings", "size"])?pizza_done為信號名字,根據自己的需求寫就好,觸發的時候需要的兩個參數關鍵字參數toppings、size
注冊信號
def callback(sender, **kwargs):print("callback")print(sender,kwargs)pizza_done.connect(callback)觸發信號
from 路徑 import pizza_donepizza_done.send(sender='seven',toppings=123, size=456)觸發的時候就是我們使用我們自定義的信號.send(sender='seven',toppings=123, size=456) 這個sender隨便寫不影響,
由于內置信號的觸發者已經集成到Django中,所以其會自動調用,而對于自定義信號則需要開發者在任意位置觸發。也就是說我們也可以自定義一下當年某個條件達到觸發要求的時候我們自定義的信號就會觸發。
?內置信號的示列
models.py的代碼
from django.db import models# Create your models here. class UserInfo(models.Model):nid = models.AutoField(primary_key=True)username = models.CharField(max_length=32)password = models.CharField(max_length=32)def __str__(self):return self.username?
?
views.py的代碼
from django.shortcuts import render,HttpResponse from app01 import models# Create your views here. def test(request):models.UserInfo.objects.create(username='admin', password='admin')return HttpResponse('OK')?
?
信號的代碼可以寫在項目下的__init__.py下也可以寫單獨建一個.py的文件只需要在__init__.py里面導入就好
from django.db.models.signals import pre_save,post_savedef pre_save_func(sender,**kwargs):print("pre_save_func")print("pre_save_msg:",sender,kwargs)def post_save_func(sender,**kwargs):print("post_save_func")print("post_save_msg:",sender,kwargs)pre_save.connect(pre_save_func) #把函數注冊到pre_save里面 models對象保存前觸發callback函數 post_save.connect(post_save_func) #把函數注冊到post_save里面 models對象保存后觸發函數?
我們訪問前面寫的路由關系
后臺打印的信息
pre_save_func pre_save_msg: <class 'app01.models.UserInfo'> {'signal': <django.db.models.signals.ModelSignal object at 0x03D98310>, 'instance': <UserInfo: admin>, 'raw': False, 'using': 'default', 'update_fields': None} [01/Aug/2018 16:06:12] "GET /test/ HTTP/1.1" 200 2 post_save_func post_save_msg: <class 'app01.models.UserInfo'> {'signal': <django.db.models.signals.ModelSignal object at 0x03D98370>, 'instance': <UserInfo: admin>, 'created': True, 'update_fields': None, 'raw': False, 'using': 'default'}?
比較打印結果我們可以看出保存成功后的instance后面有一個鍵值對為'created': True
我們還可以使用裝飾起來觸發信號,上面的__init__.py改寫為
這個信號為請求結束再觸發
from django.core.signals import request_finished from django.dispatch import receiver@receiver(request_finished) # 請求結束后觸發這個信號 def callback(sender, **kwargs):print("Request finished!")?
我們可以看到的效果為當我們發起請求整個請求結束后會在后臺打印"request finished"
?
轉載于:https://www.cnblogs.com/yang-China/p/9363909.html
總結
以上是生活随笔為你收集整理的Django之缓存和信号的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 艺品商城总结
- 下一篇: 从零开始学PowerShell(8)创建