【问题标题】:Is it possible cache the whole page in Django?是否可以在 Django 中缓存整个页面?
【发布时间】:2019-06-20 22:43:54
【问题描述】:

我目前在this website 工作。问题是页面需要 3-4 秒才能获得第一个再见,我认为这是因为在页面中加载数据的查询非常慢。

在商店页面中,它基本上是使用商店的一个对象来显示商店的基本信息,并使用 ForeignKey 关系来访问商店的图像。此外,它使用 ManyToManyField 来访问商店的类似商店,它们也是商店对象。为了解决这个问题,我使用了 prefetch_related 和 select_related ,从而最大限度地减少了许多重复查询。但它仍然显示出低性能。

之后我想,我可以通过缓存来改进它,所以我做了下面的事情。老实说,我对缓存的期望就像超快速加载一样,因为它应该存储所有已处理的查询并只显示来自请求缓存的数据。但是,老实说,它仍然显示了 3-4 秒的加载性能。我是否以错误的方式使用缓存?

settings.py

...
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'django_cache',
    }
}
...

views.py

class StoreDetailView(View):
    def get(self, request, *args, **kwargs):
        store_domainKey = self.kwargs['store_domainKey']

        cache_store = 'store-{0}'.format(store_domainKey)
        store = cache.get(cache_store, None)
        if not store:
            try:
                q = (
                    Store.objects
                    .select_related('price_range')
                    .prefetch_related(
                        'top_keywords', 'sub_keywords', 'ship_to', 'likes',
                        'question_set', 'question_set__answer_set',
                        'similar_stores', 'sponsored_stores', 'image_set'
                    )
                    .get(domainKey=store_domainKey)
                )
            except Store.DoesNotExist:
                raise Http404
            cache.set(cache_store, q)
            store = cache.get(cache_store)


        cache_similar_stores = 'similar-stores-{0}'.format(store_domainKey)
        similar_stores = cache.get(cache_similar_stores, None)
        if not similar_stores:
            sponsored_stores_ids = sponsored_stores.values_list('sponsor_receiver__id', flat=True)
            q = (
                Similarity.objects
                .select_related('similar_store', 'similar_store__price_range')
                .prefetch_related('similar_store__image_set')
                .filter(similar_target=store)
                .exclude(Q(similar_store__id__in=sponsored_stores_ids) | Q(similar_store=store))
            )
            cache.set(cache_similar_stores, q)
            similar_stores = cache.get(cache_similar_stores)


        page = request.GET.get('page', 1)
        paginator = Paginator(similar_stores, 5)
        try:
            similar_stores = paginator.page(page)
        except PageNotAnInteger:
            similar_stores = paginator.page(1)
        except EmptyPage:
            similar_stores = paginator.page(paginator.num_pages)


        context = {
            'store': store,
            'sponsored_stores': sponsored_stores,
            'similar_stores': similar_stores,
            'top_3_similar_store_string': top_3_similar_store_string,
        }


        return render(request, template, context)

【问题讨论】:

  • 查看 python 分析。你不应该在没有首先弄清楚是什么导致代码变慢的情况下优化代码——否则你可能只是在浪费自己的时间。

标签: django django-cache


【解决方案1】:

上面关于分析的评论绝对值得考虑,但要回答这个问题,我通常会使用 mixin 缓存基于通用类的视图。例如:

from django.views.decorators.cache import cache_page
from django.views.generic import View

class CacheMixin(object):
    cache_timeout = 3600 * 24 * 7

    def get_cache_timeout(self):
        return self.cache_timeout

    def dispatch(self, *args, **kwargs):
        return cache_page(self.get_cache_timeout())(super().dispatch)(*args, **kwargs)

class StoreDetailView(CacheMixin, View):
    def get(self, request, *args, **kwargs):
    ...

您也可以使用片段缓存在模板级别进行缓存,但必须小心将上下文中的任何变量作为模板片段标识符的一部分。

Django 调试工具栏对于识别有问题的查询及其来源非常有帮助。

祝你好运!

【讨论】:

  • 这正是我想要的,谢谢!顺便说一句,当我使用from django.core.cache import cache 时,我可以通过执行cache.delete(STORE_ID) 或类似的操作在Django admin 中保存或删除对象时删除缓存。 cache_page 也支持吗?我试图查找它,但没有发现任何有用的东西
  • 不幸的是,如果不查找缓存键并使用cache.delete(),我认为没有简单的方法可以做到这一点。如果你觉得答案有帮助,你能把它标记为正确吗?我很高兴它对你有用!
  • 当然!它已经帮助了我很多,感谢您检查是否也有删除页面缓存的方法!
猜你喜欢
  • 2011-07-08
  • 1970-01-01
  • 1970-01-01
  • 2015-12-22
  • 2011-02-21
  • 1970-01-01
  • 2013-12-31
  • 1970-01-01
  • 2010-09-21
相关资源
最近更新 更多