Я хотел бы сохранить список запросов «Последнее посещение» 20 в представлении Django. Также я хочу избежать создания отдельной модели для нее и просто сохранить запрошенные URL-адреса в memcached, нажав каждый новый запрос на очередь фиксированного размера и затем получить очередь в представлениях. Но поскольку кеш - это просто ключ: словарь значений. Мне интересно, как лучше всего это достичь?Как кешировать список запросов в представлениях Django?
ответ
Одним из способов сделать это с помощью memcache было бы хранить маринованный объект python в виде одного ключа в кеше.
В этом случае мы могли бы использовать Python deque, который имеет точно свойства, которые мы бы хотели получить список 20 самых последних пунктов
Каждый раз, когда мы записываем новый вид страницы нам нужно обновить Deque, который означает получить его, раскрыть, добавить, рассолить и установить новое значение обратно в memcache.
К счастью, кэш-память Django будет обрабатывать травление и раскатывание для нас. Однако мы должны позаботиться о возможности гонки - другими словами, если другой процесс также обновит deque после того, как мы получим нашу копию, и прежде чем у нас появится возможность вернуть ее в кеш.
По этой причине мы должны использовать операцию memcache CAS ('сравнение и набор'). Существует расширенные Джанго бэкэнды что позволяет CAS доступны здесь:
https://github.com/anentropic/django-cas-cache
pip install django-cas-cache
Мы бы некоторый код в пользовательском Django middleware для обновления кэша на каждой страницу, глядя примерно так:
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
v iews.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',
)
Ницца! но нам нужно будет кэшировать как 'request.path', так и' article.title', если мы хотим избежать любых ударов базы данных для рендеринга 'last_seen'. Как с этим справиться? – Jand
хорошо, вам нужно разобраться в деталях промежуточного программного обеспечения, специфичного для вашего случая (например, откуда происходит экземпляр 'article'), но вы можете добавить кортежи' (request.path, article.title) 'в deque, а не просто 'request.path' – Anentropic
Часть проблема в том, что это именно то, что РСУБД был разработан и не в рубке Memcached в. – FlipperPA
@FlipperPA: почему сохранить список в кеше такой плохой идеей, а можно исключить попадание базы данных для каждого запроса? – Jand
это было бы намного проще, если бы вы могли использовать Redis вместо memcached – Anentropic