對於非經常更新的服務器數據,若每次都從硬盤讀取一次,會浪費服務器資源、拖慢響應速度,而且數據更新頻率較高,服務器負擔比較大。若保存到數據庫,還需要額外建立一張對應的表存儲數據。一個更好的方法是在Django中使用Redis進行緩存。
緩存配置
首先安裝django-redis:
pip install django-redis
在setting文件中設置CACHES:
CACHES = {
'default':{
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION':"redis://you_host:you_port/1",
'TIMEOUT': 200, # NONE 永不超時
'OPTIONS':{
"PASSWORD":"you_passwd",#密碼,沒有可不設置
'CLIENT_CLASS': 'django_redis.client.DefaultClient', #redis-py 客戶端
'PICKLE_VERSION': -1, # 插件使用PICKLE進行序列化,-1表示最新版本
'CONNECTION_POOL_KWARGS': {"max_connections": 100}, # 連接池最大連接數
'SOCKET_CONNECT_TIMEOUT': 5, # 連接超時
'SOCKET_TIMEOUT': 5, # 讀寫超時
}
#"KEY_PREFIX ":"test",#前綴
}
}
配置好後運行程序,進行測試:
引入庫
>>>from django.core.cache import cache
>>>cache.set("test","abscd",30)
True
同時查看redis-cli客戶端是否寫入:
已經寫入redis,說明配置沒問題。
緩存
1.視圖緩存
緩存框架通用的方法就是緩存視圖函數,在需要進行緩存的視圖函數文件中引入django.views.decorators.cache定義的裝飾器cache_page,它可以自動緩存視圖:
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def my_view(request):
...
在上面的例子裏,cache_page 使用了一個參數:緩存過期時間,以秒爲單位。my_view() 視圖的結果將緩存15分鐘。(注意,用 60 * 15 這樣的方式編寫,目的是方便閱讀, 也就是15分鐘),查看一下cache_page函數的定義:
def cache_page(timeout, *, cache=None, key_prefix=None):
"""
timeout:爲上面設置的超時時間;
cache:可以指定使用哪個緩存;
key_prefix:緩存鍵值的前綴,如果setting裏設置了KEY_PREFIX,它的鍵值將與KEY_PREFIX連接起來redis裏緩存
可以這樣使用,指定超時時間、指定使用哪個緩存、指定鍵名前綴
@cache_page(60 * 15, cache="special_cache",key_prefix="site1")
def my_view(request):
...
2.在 URLconf 中指定視圖緩存
視圖緩存還可以在url上進行。打開urls.py文件,引入相應的庫,將需要緩存的url視圖用cache_page包裹:
from django.views.decorators.cache import cache_page
urlpatterns = [
path('foo/<int:code>/', cache_page(60 * 15)(my_view)),#緩存將保留15分鐘
]
這樣如果url (比如 /foo/23/ )已經被請求,那麼隨後的請求都將使用緩存,每個url都將被單獨緩存。
3.在模板中進行緩存
在模板文件中使用緩存需要在頂部先引入 {% load cache %} ,然後就可以使用 {% cache %} 標籤進行緩存操作,使用緩存標籤至少需要提供兩個參數,一個是超時時間、一個是鍵名,如:
{% load cache %}
{% cache 500 sidebar %}#500爲緩存時間,sidebar爲緩存片段名稱
.. sidebar ..
{% endcache %}
如果想爲每個登錄用戶單獨緩存的話,可以這樣:
{% load cache %}
{% cache 500 sidebar request.user.username %} #增加了用戶這個參數,通常網站緩存還是得以用戶爲基準
.. sidebar for logged in user ..
{% endcache %}
注意:這裏的緩存失效時間500可以爲一個模板變量 ,{% cache my_var sidebar %} 可以從後端傳遞過來。
底層API
剛纔介紹的都是基於頁面的緩存,有時候我們並不想把頁面所有內容都緩存,有些可變內容也不適合緩存,對於這些情況django提供了一些緩存api用於更細粒度的緩存,在django文檔中所說,可以被pickle的python對象都可以緩存,這就包括:模型對象的字符串、字典、列表,大部分python對象都可以被pickle。
1.訪問緩存
django.core.cache.caches
對caches的操作基本與對字典操作一樣。
>>from django.core.cache import caches
>>cache1 = caches['myalias']
>>cache2 = caches['myalias']
cache1 is cache2
True
但是當我們訪問一個不存在的鍵的時候,將會拋出InvalidCacheBackendError 錯誤。這時我們可以使用:
from django.core.cache import cache
2.基本用法
cache.set(key, value, timeout=DEFAULT_TIMEOUT, version=None)
>> cache.set('my_key', 'hello, world!', 30)
cache.get(key, default=None, version=None)
>>> cache.get('my_key')
'hello, world!'
key 是一個字符串,value 可以pickle 的Python 對象。
timeout 參數是可選的,默認爲 CACHES 中相應後端的 timeout 參數。timeout 設置爲 None 時將永久緩存,timeout 爲0將不緩存值。
如果對象不在緩存中,cache.get() 將返回 None。
建議不要在緩存中存儲爲 None 的值,因爲你不能分辨是你存儲的 None 值還是因爲緩存命中返回的 None 值。
cache.add(key, value, timeout=DEFAULT_TIMEOUT, version=None)
在鍵不存在的時候,使用 add() 方法可以添加鍵。它與 set() 帶有相同的參數,但如果指定的鍵已經存在,將不會嘗試更新緩存。
>>> cache.set('add_key', 'Initial value')
>>> cache.add('add_key', 'New value')
>>> cache.get('add_key')
'Initial value'
#cache.get("add_key"," new_value"),get方法還可以像字典一樣沒有得到值的話返回一個默認值“new_value”
cache.get_or_set(key, default, timeout=DEFAULT_TIMEOUT, version=None)
如果你想得到鍵值或者如果鍵不在緩存中時設置一個值,可以使用 get_or_set() 方法。
>>> cache.get('my_new_key') # returns None
>>> cache.get_or_set('my_new_key', 'my new value', 100)
'my new value'
cache.get_many(keys, version=None)
cache.set_many(dict, timeout)
看示例:
>>> cache.set('a', 1)
>>> cache.set('b', 2)
>>> cache.set('c', 3)
>>> cache.get_many(['a', 'b', 'c'])#列表作爲參數
{'a': 1, 'b': 2, 'c': 3}
>>> cache.set_many({'a': 1, 'b': 2, 'c': 3})#字典作爲參數
>>> cache.get_many(['a', 'b', 'c'])
{'a': 1, 'b': 2, 'c': 3}
cache.delete(key, version=None)
cache.delete_many(keys, version=None)
>>> cache.delete('a') #刪除一個鍵
>>>> cache.delete_many(['a', 'b', 'c'])#一次性刪除多個
cache.incr(key, delta=1, version=None)
cache.decr(key, delta=1, version=None)
使用 incr() 或 decr() 方法來遞增或遞減一個已經存在的鍵的值,遞增或遞減一個不存在的緩存鍵,將會引發 ValueError 錯誤。
>>> cache.set('num', 1)
>>> cache.incr('num')
2
>>> cache.incr('num', 10)
12
>>> cache.decr('num')
11
>>> cache.decr('num', 5)
6
cache.touch(key, timeout=DEFAULT_TIMEOUT, version=None)
cache.touch() 爲鍵設置一個新的過期時間。比如,更新一個鍵,過期時間爲10秒鐘
>>> cache.touch('a', 10)
True
使用 Vary 頭
默認情況下我們的對 (http://www.happyhong.cn/)這個鏈接的緩存對於所有訪問者都是一樣的,不能針對不同用戶代理進行區別緩存,如果想使用基於cookies、user-agent的不同進行緩存,就需要使用django提供的 django.views.decorators.vary.vary_on_headers() 視圖裝飾器,像這樣:
from django.views.decorators.vary import vary_on_headers
@vary_on_headers('User-Agent')
def my_view(request):
...
Django 自帶的緩存中間件將爲每一個用戶代理即user-agent緩存一個獨立的頁面版本,傳遞給 vary_on_headers 的頭是不區分大小寫的;“User-Agent” 和 “user-agent” 是一樣的。
可以傳遞多個頭參數給 vary_on_headers():
@vary_on_headers('User-Agent', 'Cookie')
def my_view(request):
...
這就意味着要根據每個用戶代理和 cookie 的組合來獲取它自己的緩存值。
使用其它頭控制緩存
from django.views.decorators.cache import cache_control
@cache_control(private=True)
def my_view(request):
關於cache_control後續再更新吧,更多爬蟲、django相關、軟件安裝請移步從今天開始種樹。。。