Django基础:在Django中使用redis作为缓存

发布于 2020-11-27  1,708 次阅读


缓存(Cache)对于创建一个高性能的网站和提升用户体验来说是非常重要的,今天我们就来看看缓存Cache应用场景及工作原理吧,并详细介绍如何在Django中设置Cache并使用它们。

  1. 提高服务器查询性能,因为放在缓存服务器中的数据一般都是存储在内存当中的,内存中的数据读写效率更高
  2. 减少服务器端的压力,提高服务器的查询性能
  3. 减少数据库频繁查询的压力,提升mysql的使用率

一、cache介绍

由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存。

缓存工作原理:缓存是将一些常用的数据保存内存或者memcache中,在一定的时间内有用户来访问这些数据时,则不再去执行数据库及渲染等操作,而是直接从内存或memcache的缓存中去取得数据,然后返回给用户。

Django提供了6种缓存方式:

  • 开发调试缓存
  • 内存缓存
  • 文件缓存
  • 数据库缓存
  • Memcache缓存(使用python-memcached模块)
  • Memcache缓存(使用pylibmc模块)

这里不多介绍,有兴趣的可以去看看官方文档:https://docs.djangoproject.com/en/dev/topics/cache/

二、Redis缓存

Redis可以干什么?

记录评论数、热度、浏览量等。(使用hash)

记录我的收藏、我的文章等列表类型的数据。(使用zset)

记录某篇文章的点赞人员列表。(使用zset)

缓存频繁访问但又不太多的东西,例如:热门推荐。(使用hash)

记录与当前浏览的对象相关的对象,例如:与当前文章相关的文章。(使用list)

记录分类排行榜。(使用zset)

缓存历史记录,如:登录历史等。(使用zset或hash)

Redis的数据结构

不管什么数据类型,在Redis总是以key,value的形式存在,可以通过key获得value的值,redis数据结构类型的差异取决于value的类型。

例如:string类型的value是string,set类型的value是set,zset的value的类型是zset,而key都是string。

=========================================================================================
string(字符串)       {"key1":"hello Wrold" }  
set(集合)            {"key2":{'a':null,'b':null}}      set相当于字典,只是所有键对应的值都是null
zset(有序集合)        有顺序的set      
hash(字典)          {"key3":{'url1':'http://22'}}     可以用来存储用户信息
list(列表)           {"key4": [1,2,4,3]                 
=========================================================================================

string的应用

常见的用途:缓存用户基本信息。
将用户的基本信息序列化成JSON字符串,然后将序列化后的字符串保存到 Redis 来缓存。反过来,当取用户
信息时,会经过一次反序列化。

list的应用

通常用作异步队列、存储列表数据。

hash的应用

无序字典,字典的值只能是字符串。

hash的最后一个元素删除后,该数据结构自动被删除。

hash也可以存储用户的信息,和string不同的是,hash可以对用户信息的每个字段单独存储。

set集合的应用

set的最后一个元素删除后,该数据结构自动被删除。

set中不存在重复元素,利用这个特性,我们可以用来存储防止重复事件发生的情况。例如:在抽奖活动系统中存储中奖用户,防止重复中奖。

Django-Redis

安装 pip install django-redis

Django 支持 Redis cache/session 后端的全功能组件。

说明

Django-Redis可以和Django配合使用,充当cache/session

Django-Redis依赖于pyredis

功能

作为session后端

SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"

作为cache后端

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}

三、应用

全站使用缓存

使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用 FetchFromCacheMiddleware 获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware 会将缓存保存至缓存,从而实现全站缓存。

MIDDLEWARE = [
    'django.middleware.cache.UpdateCacheMiddleware',  # 放在第一
    # 其他中间件...
    'django.middleware.cache.FetchFromCacheMiddleware',  # 放在最后
]

CACHE_MIDDLEWARE_ALIAS = ""          # 用于存储的缓存别名
CACHE_MIDDLEWARE_SECONDS = 600       # 每个页面应缓存的秒数 
CACHE_MIDDLEWARE_KEY_PREFIX = ""     # 如果使用相同的Django安装在多个站点之间共享缓存,请将其设置为站点名称或此Django实例特有的其他字符串,以防止发生密钥冲突。如果你不在乎,请使用空字符串。

Django代码中如何使用Cache

当你做好Cache的设置后,在代码中你可以有三种方式使用Cache。

  • 在视图View中使用
  • 在路由URLConf中使用
  • 在模板中使用

单独视图缓存(记得取消全站缓存中间件配置)

当用户首次访问博客首页时,我们从数据库中提取文章列表,并将其存储到缓存里(常用的是内存,这取决于你的设置)。当用户在单位时间内再次访问首页时, Django先检查缓存是否过期(本例是15分钟), 再检查缓存里文章列表资源是否存在,如果存在,直接从缓存中读取数据, 并渲染模板。

from django.shortcuts import render
from django.views.decorators.cache import cache_page


@cache_page(60 * 15)  # 秒数,这里指缓存 15 分钟
def index(request):
    article_list = Article.objects.all()
    return render(request, 'index.html', {'article_list': article_list})

模板局部缓存

# 1.引入TemplateTag
{% load cache %}

# 2.使用缓存
{% cache 600 name %}  # 第一个参数表示缓存时间,第二个参数是key值(取缓存的时候,需要根据key值取)
  缓存内容
{% endcache %}

在路由URLConf中使用cache

前一节中的范例将视图硬编码为使用缓存,因为 cache_page 在适当的位置对 my_view 函数进行了转换。 该方法将视图与缓存系统进行了耦合,从几个方面来说并不理想。 例如,你可能想在某个无缓存的站点中重用该视图函数,或者你可能想将该视图发布给那些不想通过缓存使用它们的人。 解决这些问题的方法是在 URLconf 中指定视图缓存,而不是紧挨着这些视图函数本身来指定。

完成这项工作非常简单: 在 URLconf 中用到这些视图函数的时候简单地包裹一个 cache_page 。以下是刚才用到过的 URLconf : 这是之前的URLconf:

urlpatterns = ('',
    (r'^foo/(\d{1,2})/$', my_view),
)

以下是同一个 URLconf ,不过用 cache_page 包裹了 my_view :

from django.views.decorators.cache import cache_page

urlpatterns = ('',
    (r'^foo/(\d{1,2})/$', cache_page(my_view, 60 * 15)),
)

如果采取这种方法, 不要忘记在 URLconf 中导入 cache_page。

视图中连接(手动操作redis):

from django.shortcuts import HttpResponse
from django_redis import get_redis_connection

def index(request):
    r = get_redis_connection("default")
    r.hmset("name_a", {"key_a": "value_a", "key_b": "value_b"})
    return HttpResponse("设置redis")

一名测试工作者,专注接口测试、自动化测试、性能测试、Python技术。