【Django】使用django-redis作为项目缓存

在业务中涉及操作两个数据库的查询操作, 一定会面临数据一致性的问题。 Mysql中数据可能是最实时的,redis会延后30s。牺牲数据的实时性来换取查询性能。

缓存使用场景

短时间缓存:解决高并发带来的数据库查询压力,缓存的生命周期定义在业务合理的范围内

长时间缓存:将长时间不会发生任何更改的查询结果缓存起来,减少了查数据库的操作,提高了性能。


安装

pip install django-redis

 安装这个库需要django版本大于2.2


设置

# settings.py

CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/3', #redis默认有16个库,后面数字可设定使用几号库
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient'
        }
    },
}

缓存激活

python manage.py createcachetable

测试是否激活成功

python manage.py shell

>>> from django.core.cache import cache
>>> cache.set("test_key", "test_value")
True

视图缓存

from django.views.decorators.cache import cache_page

# 给函数加上装饰器,参数为缓存的秒数
@cache_page(60 * 15)
def my_view(request):
    ...

# 类缓存写法
from django.utils.decorators import method_decorator

# 此方法会给所有类方法添加缓存
@method_decorator(cache_page(60 * 15), name='dispatch')
class MyView(View):
    def get(self, request, pk):
        ...
        pass


# 此方法给类方法单独添加缓存
class MyView(View):
    @method_decorator(cache_page(60 * 15))
    def get(self, request, pk):
        ...
        pass

自定义缓存

设置缓存

from django.core.cache import cache


redis_key = "archive_cache"
redis_value = ...
cache.set(redis_key, json.dumps(redis_value))
# 设置缓存时长
cache.expire(redis_key, 30)

读取缓存

cache.get(redis_key)

对象缓存

若要将对象进行缓存,需要将对象转换为json存到redis缓存中,然后从redis缓存中获取json数据,再反序列化为对象

设置缓存

article_list = Article.objects.all()

archive_dict = {}
for article in article_list:
    year = article.create_time.strftime("%Y")
    # 如果当前字典没有目标key, 则给定默认值
    # 如果当前字典有目标key, 则无变化
    archive_dict.setdefault(year, {"year": year, "article_list": []})
    archive_dict[year]['article_list'].append(article)

    context = {
        "archive_list": archive_dict.values(),
        "article_count": len(article_list)
    }

    # 缓存archive_list
    serializer_archives = []
    for archive in archive_dict.values():
        serializer_archives.append({
            "year": archive['year'],
            "article_list": serializers.serialize("json", archive['article_list'])
        })
    cache.set(redis_key, json.dumps(serializer_archives))
    cache.expire(redis_key, 30)

读取缓存

redis_value = cache.get(redis_key)
        if redis_value:
            print("hit cache")
            serializer_archives = json.loads(redis_value)
            archive_list = []
            article_count = 0
            for archive in serializer_archives:
                # 为了模板可以正常渲染, 需要将article反序列化为对象
                archive_list.append({
                    "year": archive['year'],
                    "article_list": [obj.object for obj in serializers.deserialize('json', archive['article_list'])]
                })
                article_count += len(archive['article_list'])

            context = {
                "archive_list": archive_list,
                "article_count": article_count
            }

这里的缓存存取方式略显繁琐,可以引入django rest framework配合使用,序列化器简单强大,灰常好用,可以看鄙人的另一篇文章https://blog.csdn.net/Runaway_pilot


进阶使用

永不超时设置

django-redis 支持永不超时的设置。

  • timeout=0 立即过期
  • timeout=None 永不超时
cache.set("key", "value", timeout=None)

获取生存时间

在 redis 中,我们可以获取任何 key 的 ttl(time to live), django-redis 也同样支持获取 ttl

  • 0 :key 不存在 (或已过期).
  • None :key 存在但没有设置过期.
  • ttl :任何有超时设置的 key 的超时值.

 以 keys 搜索过期:

>>> from django.core.cache import cache
>>> cache.set("foo", "value", timeout=25)
>>> cache.ttl("foo")
25
>>> cache.ttl("not-existent")
0

expire和 persist

使用 persist 可以让一个值永久存在

使用 persist 的例子:

>>> cache.set("foo", "bar", timeout=22)
>>> cache.ttl("foo")
22
>>> cache.persist("foo")
>>> cache.ttl("foo")
None

使用 expire 可以指定一个新的过期时间

使用 expire 的例子:

>>> cache.set("foo", "bar", timeout=22)
>>> cache.expire("foo", timeout=5)
>>> cache.ttl("foo")
5

检索和删除

django-redis 支持使用全局通配符的方式来检索或者删除键。

使用通配符搜索的例子

>>> from django.core.cache import cache
>>> cache.keys("foo_*")
["foo_1", "foo_2"]

这个写法会返回所有匹配的值。但在拥有很大数据量的数据库中这样做并显然不太合适。

使用 iter_keys 取代 keys 方法, iter_keys 将返回匹配值的迭代器, 然后我们可以使用迭代器高效地进行遍历。

>>> from django.core.cache import cache
>>> cache.iter_keys("foo_*")

>>> next(cache.iter_keys("foo_*"))
"foo_1"

如果要删除键,使用 delete_pattern 方法,它也支持全局通配符, 它会会返回删掉的键的数量

>>> from django.core.cache import cache
>>> cache.delete_pattern("foo_*")
2

官方文档地址

https://django-redis-chs.readthedocs.io/zh_CN/latest/


Everything is going smoothly.

你可能感兴趣的:(Django开发,django,缓存,redis)