我想把'Last Seen' 20个请求的列表保存到Django视图中。另外,我想避免为它创建一个单独的模型,只是将请求的url保存在memcached中,通过将每个新请求推送到固定大小的队列,然后在视图中检索队列。但由于缓存只是键:值字典,我想知道如何最好地实现这一点?
使用memcache实现此目的的一种方法是将pickle python对象作为单个键存储在缓存中。
在这种情况下,我们可以使用Python deque,它具有我们想要的包含最近20项的列表的属性
每次记录一个新的页面视图时,我们都需要更新deque,这意味着获取它,解pickle它,追加它,pickle它,并将新值设置回memcache。
幸运的是,Django的缓存框架会为我们处理pickle和unpickle。然而,我们需要注意的一件事是竞争条件的可能性——换句话说,如果在我们获得副本之后,在我们有机会将其设置回缓存之前,另一个进程也更新了deque。 由于这个原因,我们应该使用memcache的CAS('比较与设置')操作。这里有一个扩展的Django缓存后端,可以使用CAS:https://github.com/anentropic/django-cas-cache
pip install django-cas-cache
我们将在自定义Django中间件中使用一些代码来更新每个页面视图的缓存,大致如下所示:
middleware.py
from collections import deque
from django.core.cache import cache
class LastSeenMiddleware(object):
def process_response(request, response):
# you might want some logic like this to only
# record successful requests
if response.status != 200:
return response
# in case we don't already have a deque, try to add
# (add will not overwrite if key already exists)
added = cache.add('last_seen', deque([request.path], maxlen=20))
if not added:
def update(val):
val.append(request.path)
return val
cache.cas('last_seen', update)
return response
views.py
from django.core.cache import cache
from django.shortcuts import render_to_response
def myview(request):
last_seen = cache.get('last_seen')
# whatever
return render_to_response('mytemplate.html', {'last_seen': last_seen})
settings.py
CACHES = {
'default': {
'BACKEND': 'cascache.backends.memcached.MemcachedCASCache',
'LOCATION': '127.0.0.1:11211',
}
}
# as a response processor, our middleware should probably come
# first in this list, in order to run *last*
MIDDLEWARE_CLASSES = (
'myapp.middleware.LastSeenMiddleware',
'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',
'django.middleware.security.SecurityMiddleware',
)