zoukankan      html  css  js  c++  java
  • Django缓存机制--rest_framework中节流源码使用的就是django提供的缓存api

    一、配置缓存
      https://www.jb51.net/article/124434.htm
    二、缓存全站、页面、局部
     
    三、自我控制的简单缓存API
    • API 接口为:django.core.chache
      存接口:cache.set(key, value, time_out)
      取接口:cache.get(key)

    django中的低层次缓存API

    有些时候,对整个经解析的页面进行缓存并不会给你带来太多好处,事实上可能会过犹不及。
    比如说,也许你的站点所包含的一个视图依赖几个费时的查询,每隔一段时间结果就会发生变化。 在这种情况下,使用站点级缓存或者视图级缓存策略所提供的整页缓存并不是最理想的,因为你可能不会想对整个结果进行缓存(因为一些数据经常变化),但你仍然会想对很少变化的部分进行缓存。
    针对这样的情况,Django提供了简单低级的缓存API。 你可以通过这个API,以任何你需要的粒度来缓存对象。 你可以对所有能够安全进行 pickle 处理的 Python 对象进行缓存: 字符串、字典和模型对象列表等等。 (查阅 Python 文档可以了解到更多关于 pickling 的信息。)
    缓存模块django.core.cache拥有一个自动依据CACHE_BACKEND设置创建的django.core.cache对象。

    使用缓存须知:默认调用settings 中的缓存配置
    如果取的key不存在默认返回None

    cache.get() 接受缺省参数:cache.get('my_key', 'has expired')
    不存在将返回:'has expired'

    自动删除没有设置超时时间、或者没超时的key
    • cache.delete(key)
       
      可以用 cache.delete() 显式地删除关键字:
       
      cache.delete('a')

    也可以使用incr()或者decr()来增加或者减少已经存在的键值。 默认情况下,增加或减少的值是1。可以用参数来制定其他值。 如果尝试增减不存在的键值会抛出ValueError。

    >>> cache.set('num', 1)
    >>> cache.incr('num')
    2
    >>> cache.incr('num', 10)
    12
    >>> cache.decr('num')
    11
    >>> cache.decr('num', 5)
    
    • 注意:
       
      incr()/decr()方法不是原子操作。 在支持原子增减的缓存后端上(最著名的是memcached),增减操作才是原子的。 然而,如果后端并不原生支持增减操作,也可以通过取值/更新两步操作来实现。
    3.2 rest_framework 源码解析
    • rest_framework中节流源码使用的就是django提供的缓存api
        def dispatch(self, request, *args, **kwargs):    
              ...
            self.args = args
            self.kwargs = kwargs
            ##############################################################
    
            request = self.initialize_request(request, *args, **kwargs)          # 1.封装request
    
            #封装后的request对象
            #return Request(
            #   request,
            #    parsers=self.get_parsers(),
            #    authenticators=self.get_authenticators(),   #获取认证对象
            #    negotiator=self.get_content_negotiator(),
            #    parser_context=parser_context
            #)
    
            #############################################################
            self.request = request
            self.headers = self.default_response_headers  # deprecate?
    
            try:
            ##############################################################
    
                self.initial(request, *args, **kwargs)   #2 初始化认证
    
            ##############################################################
                ...
            except Exception as exc:
                ...
            return self.response
    
    • 再看#2 self.initial(request, *args, **kwargs) 初始化各种认证的过程
        def initial(self, request, *args, **kwargs):
            .....
    
            # Ensure that the incoming request is permitted
    
            self.perform_authentication(request)           #3.在这儿实现认证
    
            self.check_permissions(request)             #4.权限检查
     
            self.check_throttles(request)            #5.访问频率控制
    
    • 重点看#5处,里面循化认证了频率控制:这儿就不贴出#5中的源码了
      直接将循环的类中去查看:from rest_framework.throttling import SimpleRateThrottle
    class SimpleRateThrottle(BaseThrottle):
       ...
        #实际是:from django.core.cache import cache as default_cache
        cache = default_cache   #可以看到这儿就是调用django提供的缓存api
         ...
        scope = None #这儿是配置频率,可以到配置文件中去配置,也可以继承类重写:如3/m
        ...
    
    
        def get_cache_key(self, request, view):
            """
            必须重写该方法,将缓存的 key返回:常用用户名、IP等做访问频率的控制
            如:
            return request.META.remote_addr() 或者 用户名
            """
            raise NotImplementedError('.get_cache_key() must be overridden')
    
        def get_rate(self):
            #从配置文件中拿出访问频率
            ...
    
        def parse_rate(self, rate):
            #解析配置文件中的访问频率文本
            ...
    
        def allow_request(self, request, view):
            #访问频率的控制,认证
            ...
    
            if self.rate is None:
                return True
    
            self.key = self.get_cache_key(request, view)   #从我们重写的方法中拿到缓存key
            if self.key is None:
                return True
    
            self.history = self.cache.get(self.key, [])    #从缓存中拿出用该key存的数据
            self.now = self.timer()
    
            ...
            return self.throttle_success()
    
        def throttle_success(self):
            #认证成功,重新设置缓存
            ...
            self.history.insert(0, self.now)
            self.cache.set(self.key, self.history, self.duration)  #重新设置缓存
            return True
    
    3.2.2 总结rest_framework中的频率控制流程,及cache的使用
     
    1. 引入rest_framework: from rest_framework import APIView
      APIView继承了Django中的View 也就是CBV中的View
       
      引入:SimpleThrottle:from rest_framework.throttling import SimpleThrottle
      自己的类继承SimpleThrottle:并重写 get_cache_key(self, request, view)方法,以及scope 访问频率
      如果全局使用就配置到settings.py中:DEFALUT_THROTTLE_CLASSES = [自己的访问频率控制类, ]
      如果局部:就在继承了APIView中的类:throttle_classes = [自己的访问频率控制类,]

    2. APIView 中dispatch方法封装了reqeust对象,initialize_request(request, *args, **kwargs)
      初始化方法: self.initial(request, *args, **kwargs) 初始化认证
       
      self.perform_authentication(request) #3.在这儿实现认证
       
      self.check_permissions(request) #4.权限检查
      &nbsp
      self.check_throttles(request) #5.访问频率控制
       
      def check_throttles(self, request):
      ...
      for throttle in self.get_throttles(): #循环认证我们自己的访问频率控制类
      ....if not throttle.allow_request(request, self): #调用里面的allow_request 方法
      ........self.throttled(request, throttle.wait()) #抛出异常

    3. SimpleThrottle中:cache = default_cache 调用系统提供的cache-api接口
      重写get_cache_key方法,返回自己将用来存储缓存的key

  • 相关阅读:
    POJ 1754 Splay
    POJ 3481Double Queue Splay
    前缀表达式求值
    Treap(树堆):随机平衡二叉树实现
    Tarjian算法求强联通分量
    (转)priority_queue的用法
    001Angular2环境准备
    9.富客户端应用程序的线程
    8.信号
    7.线程的优先级
  • 原文地址:https://www.cnblogs.com/shiqi17/p/9825964.html
Copyright © 2011-2022 走看看