本文节选自笔者博客:https://www.blog.zeeland.cn/archives/23r9oiasaaa
- 作者简介:大家好,我是Zeeland,全栈领域优质创作者。
- CSDN主页:Zeeland
- 我的博客:Zeeland
- Github主页: Undertone0809 (Zeeland) (github.com)
- 支持我:点赞+收藏⭐️+留言
- 系列专栏:django开发手册
- 介绍:The mixture of software dev+Iot+ml+anything
Web应用性能是非常重要的,用户访问速度和响应时间会直接影响到用户体验。对于一个需要经常访问、更新的Web应用,缓存机制是非常重要的,它可以避免频繁的数据库访问,提高网站的访问速度、降低服务器负载。本文会探讨以下几个问题:
首先,django也提供了其cache机制,通过from django.views.decorators.cache import cache_page
引入cache_page
就可以进行使用了,使用方法如下所示:
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def my_view(request):
...
当你第一次调用这个接口的时候,django会为这个接口创建一个60*15秒的缓存,当你后面再去访问的时候,访问速度就会快很多。
需要注意的是,你需要考虑缓存的刷新机制, 一般情况下,缓存不会自动刷新,你需要自己去手动更新,可以说这是一个弊端。
下面的demo是一个将cache_page结合drf的ModelViewSet
一起使用,其作用也是接口数据的缓存。
class MeasuringPointViewSet(viewsets.ModelViewSet):
queryset = models.MeasuringPoint.objects.all().order_by('mpoint_id')
serializer_class = MeasuringPointSerializer
@method_decorator(cache_page(60 * 60))
def list(self, request, *args, **kwargs):
"""根据项目获取所有测点"""
project_id = request.query_params.get('project_id')
queryset = self.get_queryset().filter(project_id=project_id)
serializer = self.get_serializer(results, many=True)
return paginator.get_paginated_response(serializer.data)
对于上面提到的缓存刷新问题,可以使用DRF自带的缓存方法进行数据更新时的自动清除。
pip install drf-extensions
views.py
中引入缓存类:from rest_framework_extensions.cache.decorators import cache_response
@method_decorator(cache_page(60 * 60))
为@cache_response(key_func='get_cache_key')
,并添加get_cache_key
函数:class MeasuringPointViewSet(viewsets.ModelViewSet):
queryset = models.MeasuringPoint.objects.all().order_by('mpoint_id')
serializer_class = MeasuringPointSerializer
@staticmethod
def get_cache_key(request, *args, **kwargs):
project_id = request.query_params.get('project_id')
return f'{request.path}?project_id={project_id}'
@cache_response(key_func='get_cache_key')
def list(self, request, *args, **kwargs):
"""根据项目获取所有测点"""
paginator = CustomPagination()
project_id = request.query_params.get('project_id')
queryset = self.get_queryset().filter(project_id=project_id)
results = paginator.paginate_queryset(queryset, request)
serializer = self.get_serializer(results, many=True)
return paginator.get_paginated_response(serializer.data)
这里的get_cache_key
函数根据请求的URL和参数构建出缓存的Key值,以避免不同参数的请求缓存混淆。
现在每次数据更新时,DRF会自动清除缓存,确保获取到的数据是最新的。
@cache_response
和@cache_page
都是DRF提供的用来缓存视图函数返回结果的装饰器,它们之间的区别在于缓存的级别以及缓存使用的位置不同。
@cache_response
缓存的是响应的结果,因此对于同一个请求,如果响应内容不同,那么它们的缓存结果也会不同。而@cache_page
则是缓存的整个页面,因此无论响应内容是否相同,对于同一个请求,它们的缓存结果是相同的。
另外,@cache_response
是一个更加细粒度的缓存策略,因为它只缓存了响应,这样可以避免将不同的请求的数据混在一起。而@cache_page
则是更加粗粒度的缓存策略,由于缓存了整个页面,因此会引发数据混淆的问题,需要对缓存的内容和键做更严格的控制。
因此,一般情况下,我们会优先选择使用@cache_response
来缓存响应结果,以避免数据混淆的问题。
@cache_response
的缓存持续时间是由DRF的缓存系统设置的,默认情况下,它会将缓存时间设置为None,也就是永久缓存。但是,当使用@cache_response
来缓存响应结果时,当以下任意情况出现时,缓存都会自动更新:
这些情况会触发DRF的自动缓存失效机制,它会在从缓存中获取响应结果时,先检查该缓存是否仍然有效,如果已经失效,则会调用视图函数来生成新的响应,并且更新缓存。
需要注意的是,如果你的业务需要,你也可以手动清除缓存。可以使用类似于cache.delete('cache_key')
这样的代码来手动删除指定缓存键的缓存。
cache_page
还是cache_response
,你都需要注意缓存刷新的问题。cache_response
也是无法自动刷新数据的,因为django自带的管理系统是直接修改数据库中的数据,并不会触发cache_response
的缓存更新机制,这一点一定要注意一下。所以如果你有精力,对于每一个接口你都可以编写其缓存逻辑,但是更有性价比的方案是,对于那些实在不经常更新的数据,你可以使用缓存,而对于经常更新的数据,你可以把缓存时间设置小一点。本文主要讨论DRF自动缓存的使用。我们首先介绍了如何使用@cache_response
装饰器来缓存视图函数的响应结果。这个装饰器可以提供细粒度的缓存控制,能够避免不同请求的数据混淆问题。我们还介绍了如何通过get_cache_key
函数来生成唯一的缓存键,以便于管理和查询。
DRF自动缓存机制是一个非常有用的工具,可以帮助我们优化API性能,提高Web应用的访问速度和响应时间。通过使用@cache_response
装饰器和get_cache_key
函数,我们可以实现细粒度的缓存控制,避免数据混淆问题。同时,DRF的自动缓存失效机制可以自动清除缓存,避免数据不一致的问题。