[Django 0-1] Core.Cache模块

Caching 源码分析

Django 的 cache 缓存机制,包含了一些代理设计模式(代理了但没完全代理,多此一举)。

通过实现一个CacheHandler的manager类,来实现多缓存后端的统一管理和调用,避免到处实例使用。

缓存的目的

缓存的目的就是为了提高系统的性能.

  1. 存储一些变化少的热点数据,减少对数据库的访问次数
  2. 存储临时数据, 降低数据库的压力
  3. 存储计算结果, 降低计算的压力

缓存框架要考虑的方面

  1. 缓存的淘汰策略, 超过容量 LRU, FIFO, 过期时间
  2. 缓存的存储策略, 如内存缓存, 文件缓存, 数据库缓存
  3. 缓存key的管理

代理模式

通过一个外部 Proxy 来访问真实 cache 对象的属性和方法。

这个ConnectionProxy可以学习他用到的魔法方法,但本质上和设计模式没太多关系。

整个django项目里一共出现两次,一次在cache中作为default cache的入口,一次在db中作为defult db的入口

python 复制代码
# 没啥用,直接用caches['default']代替即可
class ConnectionProxy:
    """Proxy for accessing a connection object's attributes."""

    def __init__(self, connections, alias):
        self.__dict__["_connections"] = connections
        self.__dict__["_alias"] = alias

    # 重写__getattr__方法, 使得ConnectionProxy可以像访问真实的connection对象一样访问属性和方法
    def __getattr__(self, item):
        return getattr(self._connections[self._alias], item)

    # 重写__setattr__方法, 使得ConnectionProxy可以像访问真实的connection对象一样设置属性和方法
    def __setattr__(self, name, value):
        return setattr(self._connections[self._alias], name, value)

    # 重写__delattr__方法, 使得ConnectionProxy可以像访问真实的connection对象一样删除属性和方法
    def __delattr__(self, name):
        return delattr(self._connections[self._alias], name)

    # 重写__contains__方法, 使得ConnectionProxy可以使用 `key in ConnectionProxy`的语法来判断key是否存在于缓存中, 实际实现在BaseCache的各个子类中实现
    def __contains__(self, key):
        return key in self._connections[self._alias]

    # 重写__eq__方法, 使得ConnectionProxy可以使用 `ConnectionProxy == other`的语法来判断两个ConnectionProxy是否指向同一个缓存对象, 实际实现在BaseCache的各个子类中实现
    # 其实可以用total_ordering装饰器来实现__eq__方法, 但是为了保持一致性, 这里还是自己实现
    def __eq__(self, other):
        return self._connections[self._alias] == other

缓存基础类

可以学习的地方

  1. 参数默认值, 通常避免使用一些可变容器对象(list, dict),因为如果代码不严谨,容易出错。
    但是编辑器提示的时候,会告诉你默认值是 None,失去了一定的可读性。

所以可以参照 Django 的做法,使用一个名字对象来代替默认值参数。

python 复制代码
# 通常做法
def get_backend_timeout(self, timeout=None):
    """
    Return the timeout value usable by this backend based upon the provided
    """
    if timeout is None:
        timeout = self.default_timeout
    return timeout

# 改进做法
DEFAULT_TIMEOUT = object() # python模块单例
def get_backend_timeout(self, timeout=DEFAULT_TIMEOUT):
    """
    Return the timeout value usable by this backend based upon the provided
    """
    if timeout is DEFAULT_TIMEOUT: # is 比较内存地址
        timeout = self.default_timeout
    return timeout
  1. contains方法

实现 contains 方法可以改变in操作的结果

python 复制代码
    def __contains__(self, key):
        """
        Return True if the key is in the cache and has not expired.
        """
        # This is a separate method, rather than just a copy of has_key(),
        # so that it always has the same functionality as has_key(), even
        # if a subclass overrides it.
        return self.has_key(key)

总结

其他部分就是 BaseCache 的子类了,用对应的 client 实现缓存的方法。

相关推荐
学测绘的小杨10 小时前
CompassFusion:一个从 GNSS 到 GNSS/INS 组合导航的独立工程包
python
zzzzzz31017 小时前
当产品经理说这个很简单:我用Python自动化处理奇葩需求的实战指南
python·pycharm·产品经理
雪隐17 小时前
个人电脑玩AI-06让5060 Ti给你打工——不光能画画,Qwen3-TTS还能学人说话,连我老板都信了!
人工智能·后端·python
兵慌码乱1 天前
面向桌面端的资产管理系统分层架构设计与核心模块实现
python·系统架构·sqlite·pyqt5·数据库设计·桌面应用开发·mvc架构
hboot1 天前
AI工程师第三课 - 机器学习基础
python·scikit-learn·kaggle
顾林海1 天前
Agent入门阶段-编程基础-Python:流程控制
python·agent·ai编程
呱呱复呱呱2 天前
Django CBV 源码解读:一个请求是怎么找到你的 get() 方法的
python·django
曲幽2 天前
刚部署的 LibreTranslate 频频翻车?我掏出了 20 年前的 StarDict 词典,用 FastAPI 搭了个本地词典翻译 API
python·fastapi·web·translate·goldendict·libretranslate·stardict·pystardict
荣码2 天前
用Streamlit给AI应用套个界面,10行代码出Web页面
java·python
兵慌码乱2 天前
基于Python+PyQt5+SQLite的药房管理系统实现:事务一致性与界面解耦全流程解析
python·sqlite·信号与槽·pyqt5·数据库设计·桌面应用开发·事务处理