为日历日期缓存Django查询集

4 投票
3 回答
2562 浏览
提问于 2025-04-16 10:43

我有一个查询,它的结果每天只会改变一次。每次有人请求这个页面时都去执行这个查询,感觉有点浪费。我正在考虑使用memcached来解决这个问题。

我该怎么开始呢?有没有人能给我一些建议或者在使用Django的缓存时需要避免的坑?我应该在模板里缓存还是在视图里缓存呢?

这个问题可能听起来有点模糊,但其实是因为我之前从来没有接触过缓存。如果有什么我可以进一步解释的,随时问我。

进一步说明

根据Ken Cochrane的说法:

  1. 这个数据多久会变化一次:相关的数据会在那一天锁定。所以,比如说,我会提取2011年1月30日的数据,我可以接受在整个一天内都使用这个缓存的副本,直到2011年1月31日再刷新一次。

  2. 我在多个地方使用这个数据吗:只在一个视图里使用。

  3. 这个数据量有多大:大约有10个模型对象,每个对象有15个字段,最大的字段是一个CharField(max_length=120)。我会使用values()把字段数量减少到大约一半。

3 个回答

0

你可以使用Python内置的 lru_cache 来根据日期缓存函数的结果,只要方法的参数是一个简单的“2021-09-22”格式的日期,而不是时间戳:

import datetime
from functools import lru_cache

@lru_cache(maxsize=1)
def my_func(date: datetime.date):
    if type(date) is not datetime.date:
        raise ValueError(f"This method is cached by calendar date, but received date {date}.")
1

首先,试着先了解这个内容。Django有一个功能,可以使用{% cache for_seconds something %}来缓存数据。只需要使用缓存标签就可以了。想了解更多,可以查看这个链接:http://docs.djangoproject.com/en/dev/topics/cache/

10

通常在决定在哪里进行缓存之前,我会问自己几个问题。

  1. 这些数据多久会变化一次?
  2. 我在多个地方使用这些数据吗?
  3. 数据量有多大?

因为我不知道你应用的所有细节,所以我会做一些假设。

  1. 你有一个视图,它要么接收一个日期,要么使用当前日期来查询数据库,提取该日期的所有日历事件。
  2. 你只在一个模板上显示这些信息。
  3. 数据量不大(少于100条记录)。

根据这些假设,你有三个选择: 1. 缓存模板 2. 缓存视图 3. 缓存查询集

通常我会选择缓存查询集,这样我可以更好地控制数据的缓存方式,并且可以在多个地方重复使用相同的缓存数据。

我发现缓存查询集最简单的方法是在相关模型的ModelManager中进行。我会创建一个像get_calender_by_date(date)这样的函数,来处理查询和缓存。以下是一个粗略的示例:

CACHE_TIMEOUT_SECONDS = 60 * 60 * 24 # this is 24 hours

class CalendarManager(models.Manager):

    def get_calendar_by_date(self, by_date):
        """ assuming date is a datetime object """
        date_key = by_date.strftime("%m_%d_%Y")
        cache_key = 'CAL_DATE_%s' % (date_key)
        cal_date = cache.get(cache_key)
        if cal_date is not None:
            return cal_date

        # not in cache get from database
        cal_date = self.filter(event_date=by_date)

        # set cal_date in cache for later use
        cache.set(cache_key, cal_date, CACHE_TIMEOUT_SECONDS)
        return cal_date

在缓存时需要注意的一些事项:

  1. 确保你存储在缓存中的对象可以被序列化。
  2. 由于memcache不知道今天是什么时候,你需要确保不要缓存过久。例如,如果是在1月21日中午缓存了24小时,那么这些日历信息会一直显示到1月22日中午,这可能不是你想要的。因此,设置查询的缓存时间时,要么设置一个较小的值让它更快过期,要么计算好缓存的时间,以便在你想要的时候过期。
  3. 确保你知道想要缓存的对象的大小。如果你的memcache实例只有16MB的存储空间,但你想存储32MB的数据,那么缓存对你来说就没什么用。

当缓存模板或视图时,你需要注意以下几点:

  1. 设置缓存超时时间不要太长,我认为你不能通过编程方式改变模板的缓存超时时间,而且它是硬编码的,所以如果设置得太高,你可能会得到过时的页面。你应该能够通过编程方式改变缓存时间,这样会更安全一些。
  2. 如果你在缓存模板,而模板上还有其他动态信息经常变化,确保只在你想要缓存一段时间的页面部分周围放置缓存标签。如果放错地方,可能会导致错误的结果。

希望这些信息能帮助你入门。祝你好运。

撰写回答