You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Django REST Framework的retrieve接口实现持久化缓存

问题根因

当前缓存方案不生效由两个Django默认配置的设计导致:

  • FileBasedCache默认最大缓存条目数MAX_ENTRIES为300,超出阈值后会自动淘汰旧缓存。你需要缓存200万条记录,新写入的缓存会持续触发淘汰逻辑,因此缓存目录始终维持极小体积,每次请求都会改写目录内容。
  • cache_page装饰器默认将Cookie、认证信息、Accept编码等请求头纳入缓存key计算,如果接口开启鉴权,不同用户访问同一条数据会生成独立缓存副本,既浪费存储空间,又会进一步加快缓存淘汰速度,无法命中公共缓存。
可行解决方案

方案1:修正现有cache_page配置(快速修复)

调整缓存后端参数,同时收紧缓存key生成规则,让同一条记录的缓存可以跨请求共享:

  1. 修改settings.py中的缓存配置:
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/home/django_cache',
        # 最大缓存条目数略大于总记录数,避免频繁触发淘汰
        'MAX_ENTRIES': 2200000,
        # 缓存满后一次性删除10%的过期/旧缓存,降低磁盘IO频率
        'CULL_FREQUENCY': 10,
        'TIMEOUT': 60 * 60 * 24 * 365,
    }
}
  1. 修改视图类的retrieve方法,清空不必要的Vary规则:
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from django.views.decorators.vary import vary_on_headers
from rest_framework import mixins, viewsets, response
from .models import Annotation
from .serializers import AnnotationSerializer

class AnnotationViewSet(
        mixins.CreateModelMixin,
        mixins.ListModelMixin,
        mixins.RetrieveModelMixin,
        viewsets.GenericViewSet
    ):
    queryset = Annotation.objects.all()
    serializer_class = AnnotationSerializer

    @method_decorator(cache_page(60 * 60 * 24 * 365, key_prefix="annotation_retrieve"))
    @method_decorator(vary_on_headers())
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return response.Response(serializer.data)

注意:如果接口返回内容会根据登录用户身份变化,不要清空Vary规则,直接使用方案2。

方案2:使用低层缓存API(更推荐,粒度精准)

cache_page是为通用页面缓存设计的,针对单资源接口,直接调用Django低层缓存API手动控制读写逻辑更灵活,缓存key直接和记录ID绑定,完全符合单条记录对应独立缓存的需求,也不会受请求头干扰:

  1. 保留方案1中调整过MAX_ENTRIES参数的CACHES配置
  2. 重写视图逻辑,增加缓存读写、更新/删除时主动失效缓存的逻辑:
from django.core.cache import cache
from rest_framework import mixins, viewsets, response
from .models import Annotation
from .serializers import AnnotationSerializer

class AnnotationViewSet(
        mixins.CreateModelMixin,
        mixins.ListModelMixin,
        mixins.RetrieveModelMixin,
        mixins.UpdateModelMixin,
        mixins.DestroyModelMixin,
        viewsets.GenericViewSet
    ):
    queryset = Annotation.objects.all()
    serializer_class = AnnotationSerializer

    def retrieve(self, request, *args, **kwargs):
        # 缓存key直接绑定记录ID,全局唯一
        cache_key = f"annotation_detail:{kwargs['pk']}"
        cached_data = cache.get(cache_key)
        if cached_data:
            return response.Response(cached_data)
        
        # 缓存未命中时查询数据库
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        data = serializer.data
        cache.set(cache_key, data, timeout=60*60*24*365)
        return response.Response(data)

    def perform_update(self, serializer):
        instance = serializer.save()
        # 数据更新时删除对应缓存,避免返回旧内容
        cache.delete(f"annotation_detail:{instance.pk}")

    def perform_destroy(self, instance):
        # 数据删除时同步清理缓存
        cache.delete(f"annotation_detail:{instance.pk}")
        instance.delete()
额外注意事项
  • 提前确认Django运行进程对/home/django_cache目录有读写权限,否则缓存写入会静默失败。
  • 文件缓存适合读多写少的冷数据场景,如果后续访问量提升,建议替换为开启持久化的Redis缓存,读写性能比磁盘文件高几个数量级。
  • 按单条序列化结果1KB估算,200万条缓存总磁盘占用约2GB,部署前请预留足够存储空间。

内容的提问来源于stack exchange,提问作者user1315621

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 16:09:22