【发布时间】:2014-01-31 18:05:12
【问题描述】:
如何缓存分页的 Django 查询集,特别是在 ListView 中?
我注意到一个查询需要很长时间才能运行,所以我正在尝试缓存它。查询集很大(超过 10 万条记录),所以我试图只缓存它的分页子部分。我无法缓存整个视图或模板,因为有些部分是用户/会话特定的并且需要不断更改。
ListView 有两个标准方法来检索查询集,get_queryset(),它返回非分页数据,paginate_queryset(),它通过当前页面过滤它。
我首先尝试在get_queryset() 中缓存查询,但很快意识到调用cache.set(my_query_key, super(MyView, self).get_queryset()) 会导致整个查询被序列化。
然后我尝试覆盖paginate_queryset(),例如:
import time
from functools import partial
from django.core.cache import cache
from django.views.generic import ListView
class MyView(ListView):
...
def paginate_queryset(self, queryset, page_size):
cache_key = 'myview-queryset-%s-%s' % (self.page, page_size)
print 'paginate_queryset.cache_key:',cache_key
t0 = time.time()
ret = cache.get(cache_key)
if ret is None:
print 're-caching'
ret = super(MyView, self).paginate_queryset(queryset, page_size)
cache.set(cache_key, ret, 60*60)
td = time.time() - t0
print 'paginate_queryset.time.seconds:',td
(paginator, page, object_list, other_pages) = ret
print 'total objects:',len(object_list)
return ret
但是,即使只检索到 10 个对象,并且每个请求都显示“重新缓存”,这也需要将近一分钟的时间来运行,这意味着没有任何内容被保存到缓存中。
我的settings.CACHE 看起来像:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
service memcached status 显示 memcached 正在运行,tail -f /var/log/memcached.log 完全没有显示任何内容。
我做错了什么?缓存分页查询以便不检索整个查询集的正确方法是什么?
编辑:我认为它们可能是 memcached 或 Python 包装器中的错误。 Django 似乎支持两种不同的 memcached 后端,一种使用 python-memcached,一种使用 pylibmc。 python-memcached 似乎默默地隐藏了缓存paginate_queryset() 值的错误。当我切换到 pylibmc 后端时,现在我收到一条明确的错误消息“来自 memcached_set:SERVER ERROR 的错误 10”,可追溯到 set 中的 django/core/cache/backends/memcached.py,第 78 行。
【问题讨论】:
-
低级缓存 API 是否在 django shell 中工作?见docs.djangoproject.com/en/1.6/topics/cache/#basic-usage
-
是的,它似乎适用于简单的不可变对象甚至基本查询集。它似乎只在缓存
paginate_queryset()返回的值时失败。
标签: python django django-models memcached django-views