Django使用缓存高级用法

缓存一般处理流程

data = get_from_cache(key)# 首先从缓存中获取数据
if data is None:
    data = get_from_db() # 缓存没有,从数据库中获取
    set_to_cache(key,data) # 将数据添加到缓存,方便下次获取
return data

Django的默认缓存接口

from django.core.cache import cache
cache.set('a',123,10) #cache.set(key,value,default=None)
a = cache.get('a')
print(a)
x = cache.incr(a)
print(a)

缓存更新问题:

起因:
  • 有两个接口 一个是查看DB字段(含有缓存:当第一次访问数据库的时候先访问缓存
    存如果缓存没有就去数据库然后再将数据库这个字段存入到缓存中)
     另一个是修改DB字段(没有缓存),当用户去修改DB字段的时候没有将修改后的DB字段
    存入缓存导致用户在使用"查看接口"的时候出现了数据不一致的错误
  • #####解决方式
    • 直接修改
    • 删除旧的数据
    • 利用过期时间淘汰旧的数据

Django改动源码,方便使用缓存

由于在一个项目中使用缓存的地方有很多,手动去在相应的接口添加缓存第一增加了开发时间, 第二可能会出现操作失误,导致缓存与数据库数据不一致问题,那么我们可以找到一个通用的方法 在项目中只要跟数据库有交互的接口肯定会用到objects和save()方法

  • get(pk/id=...):属于objects

  • save() :属于Model

  • 直接把两个方法直接放到Model中,这样以后在处理的时候直接从Model中使用

  • 在models.Model类中我们查看源码发现objects其实是Manager的一个实例

# 源码节选
def add_to_class(cls, name, value):
    # We should call the contribute_to_class method only if it's bound
    if not inspect.isclass(value) and hasattr(value, 'contribute_to_class'):
        value.contribute_to_class(cls, name)
    else:
        setattr(cls, name, value)

 manager = Manager()
            manager.auto_created = True
            cls.add_to_class('objects', manager)

  • 搞清楚之后我们就可以写相应的方法了,在项目中添加一个.py文件
from django.core.cache import cache
from django.db import models

# get()方法原先是objects.get()调用,所以是类方法
def get(cls,*args,**kwargs):
    """数据库优先从缓存获取,缓存取不到再从数据库中获取"""
    #创建 key
    pk = kwargs.get('pk') or kwargs.get('id')

    # 从缓存中获取
    if pk is not None:
        key = 'Model:%s:%s' % (cls.__name__,pk)
        model_obj = cache.get(key)
        print("get from cache-{}".format(model_obj))
        if isinstance(model_obj,cls):
            return model_obj
    # 缓存没有,直接从数据库中获取
    model_obj = cls.objects.get(*args,**kwargs)
    print("get from db -{}".format(model_obj))

    # 写入到缓存,保存一周
    key = 'Model:%s:%s' % (cls.__name__,model_obj.pk)
    cache.set(key,model_obj,604800)
    print("set to cache- {}")
    return model_obj

# get_or_create()方法原先是objects.get_or_create()调用,所以是类方法
def get_or_create(cls,*args,**kwargs):
    # 创建 key
    pk = kwargs.get('pk') or kwargs.get('id')

    #  从缓存中获取
    if pk is not None:
        key = 'Model:%s:%s' % (cls.__name__, pk)
        model_obj = cache.get(key)
        if isinstance(model_obj, cls):
            return model_obj,False

    # 执行原生的方法,并添加缓存
    model_obj,created = cls.objects.get_or_create(*args,**kwargs)

    # 添加缓存保存一周
    key = 'Model:%s:%s' % (cls.__name__, model_obj.pk)
    cache.set(key, model_obj, 604800)
    return model_obj,created


# save() 原生是是实例方法
def save_with_cache(model_save_func):
    '''通过装饰器将缓存功能添加到原生save()中'''
    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        """存入数据库后,同时写入缓存"""
        # 调用原生的Model.save() 将数据保存到数据库
        model_save_func(force_insert,force_update,using,update_fields)

        # 添加缓存
        key = 'Model:%s:%s' % (self.__class__.__name__, self.pk)
        cache.set(key,self,604800)
    return save

def to_dict(self,*ignore_fields): #ignore_fields :不想去序列化的参数(字段)  tuple类型:因为如果是列表,会持续继承,因为列表是一个引用的过程
    # 将一个model转化成一个 dict
    attr_dict = {}
    for field in self._meta.fields: # 便利所有字段
        name = field.attname # 取出字段名称
        if name not in ignore_fields: # 检查是需要忽略的字段
            attr_dict[name] = getattr(self,name) # 获取字段对应的值
    return attr_dict


def patch_model():
    '''
    动态更新Model方法

    Model 在 Django 中是一个特殊的类,如果通过继承的方式来增加或者修改原有的方法,Django会将继承的类识别为一个普通的 app.model,
    所以只能通过 monkey patch(猴子补丁) 的方法来动态修改原生类

    '''
    # 动态添加类方法 get get_or_create
    models.Model.get = classmethod(get)
    models.Model.get_or_create = classmethod(get_or_create)

    # 修改save()
    models.Model.save = save_with_cache(models.Model.save)


    # 添加 to_dict
    models.Model.to_dict = to_dict
写好相应的方法之后我们需要去加载这个文件,而且这个文件的加载时机很重要,
需要在整个项目启动前去加载这个文件,在Django中首次加载的是配置文件也就是Django工程文件
  • 在工程文件中的__init__.py中调用刚才写好的方法即可
# 项目中第一个加载文件
import pymysql
pymysql.install_as_MySQLdb()

from lib.orm import patch_model
patch_model()
  • 弄完之后我们就可以直接替换 :模型实例.objects.get()为模型实例.get()即可
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值