天天看點

Django使用redis進行緩存

對于非經常更新的伺服器資料,若每次都從硬碟讀取一次,會浪費伺服器資源、拖慢響應速度,而且資料更新頻率較高,伺服器負擔比較大。若儲存到資料庫,還需要額外建立一張對應的表存儲資料。一個更好的方法是在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用戶端是否寫入:

Django使用redis進行緩存

已經寫入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.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相關、軟體安裝請移步從今天開始種樹。。。