作为webAPI不可避免要面对并发访问量的问题,DRF也会面临同样的问题,一个企业内部的小应用,当然不会有问题,但是放到公网上的SPA可就不一定了,也许有人会说,DRF的那套是秉承Django的,而Django本身就只支持关系型的数据库,并发响应速度本来就不是关系型数据库的强项,有道理,但是遇上高并发和追求高性能是要放弃DRF了吗?非也,pyhton强大的粘合性显示出来了。

     DRF也一样可以使用Redis,只不过是用来做缓存,持久化还是得靠关系型数据库,DRF使用redis做缓存主要是靠drf-extensions和django-redis这两个插件来完成协作:

Django restframework中使用Redis缓存_DRF

安装完毕后,DRF项目里的settings里的设置贴一下,网上很多:

Django restframework中使用Redis缓存_DRF_02

注释很详细,就不介绍了,关键参数就是缓存时间,我们搭建好redis服务器,然后在序列化的时候直接应用装饰器就可以了,非常简单,直接copy别人的介绍:

drf-extensions扩展对于缓存提供了三个扩展类:

    ListCacheResponseMixin ,用于缓存返回列表数据的视图,与ListModelMixin扩展类配合使用,实际是为list方法添加了cache_response装饰器;
    RetrieveCacheResponseMixin ,用于缓存返回单一数据的视图,与RetrieveModelMixin扩展类配合使用,实际是为retrieve方法添加了cache_response装饰器;
    CacheResponseMixin ,为视图集同时补充List和Retrieve两种缓存,与ListModelMixin和RetrieveModelMixin一起配合使用(我选择使用这种)。
    三个扩展类都是在rest_framework_extensions.cache.mixins中。

    view.py

from rest_framework_extensions.cache.mixins import CacheResponseMixin

class CustomerViewSet(CacheResponseMixin,MyModelViewSet):
# class CustomerViewSet(MyModelViewSet):
    queryset =Customer.objects.all()
    serializer_class = CustomerSerializer
    filter_backends = (filters.SearchFilter,)
    search_fields = ('Name', 'Phone','DialStatu')

 

重启服务,访问customer或者对customer数据进行增删改查(但是一般将缓存设置在经常用到但不容易被更改的数据上-只读数据),数据就会写入redis。

写到这里才只是敲山震虎,网上很多教程到这里就结束了,从上面来看,确实不复杂,我们借助RDM查看redis数据,发现只是将序列化的数据简单粗暴的将其丢到一个drf-extensions封装函数计算出来的key里面。

简单是简单,但是就美滋滋了吗?不难发现,此番操作,只能应用于只读数据场合,对于有着复杂逻辑的Vue项目,我随意添加和修改了下数据,发现一定要等到缓存过期才能取到更新的数据,因为redis本身就是缓存,它只保证数据的最终一致性,不能保证数据随时一致性,有人说,把缓存时间设置短一点,比如两秒,三秒,这种被动的更新缓存,除此之外,毫无办法了吗?能在更新数据的主动更新缓存吗?答案是肯定的。

我们进入装饰器的源码process_cache_response函数里一探究竟:

其实就是计算了一个key,然后取到了超时时间timeout,其他就是将request重新包装了下,丢到缓存里面。

复杂的key我这里用不上,我改成了自定义的字符串代替,好处是能随时知道key好做过期处理。

Django restframework中使用Redis缓存_DRF_03

注释掉复杂的key字符串的运算处理,取代为我这里的手工字符串‘Pur_list_cache’,刷新下项目网页,打开RDM看看,数据的key从之前的无意义的杂乱字符串变成了我自定义的:

Django restframework中使用Redis缓存_DRF_04

key知道了,我只需要知道在啥时候去主动更新缓存就够了,当然是在装饰DRF的update,create等创建和更新函数时候去操作,于是我们继续用装饰器去装饰自定义的create函数:

Django restframework中使用Redis缓存_DRF_05

等等,redis不是用来缓存list页面的数据吗,创建单条数据的返回值还需要缓存?当然不需要,所以,我们将timeout设为0,然后回到源码里面做逻辑处理,将‘Pur_list_cache’这个key失效:

Django restframework中使用Redis缓存_DRF_06

按图示操作,啥也别动,添加上面的红框的语句,使用__qualname__内置函数,我们能将当前调用的模型的类和函数精确打印出来,当前表明我们在Pur_M_detailViewSet序列化类里做create操作,所以,有新的数据产生,那么将要更新Pur列表数据了,本来还想结合request.method做http请求类型判断,发现没必要了,qualname函数已经能精确定位自定义的序列化操作(不知道什么叫自定义序列化操作, 看我前面的文章)

Django restframework中使用Redis缓存_DRF_07

来到web前端,为了测试,我们将后台默认缓存时间设置为3600秒,刷新页面,发现redis已经缓存了数据,并且TTL为:3586

Django restframework中使用Redis缓存_DRF_08

开始创建数据:

Django restframework中使用Redis缓存_DRF_09

再回到RDM,发现redis已经更新了缓存数据,TTL又重头计时,而不是被动的等待过期,这样我们为了追求最高的性能,将后台缓存设置为None,也就是永不过期,直到有数据更新,才会重新缓存数据:

Django restframework中使用Redis缓存_DRF_10

这样我们可以利用自定义的key值,巧妙地利用__qualname__内置函数判断更新数据的逻辑点,将timeout设置为0复用装饰器给不需要缓存数据只需要修改缓存的自定义函数去使用来达到目的,

有点像的Vue的Vuex的同步状态管理,MSSQL数据库的发布订阅,redis的发布订阅,key的自定义,我们将能对redis缓存做到单键值的更新,而不用去更改全局的超时时间和清空所有缓存,做到精确控制。

虽然源码改动较大,但是建立在drf-extensions的封装逻辑比较清晰的基础上的,并未做大的改动,有能力的可以重写key_func函数,不必像我这样全部注销掉。

 

全文完。