Django配置缓存机制

Django 官方关于cache的介绍:https://docs.djangoproject.com/en/dev/topics/cache/

Django 是动态网站,一般来说需要实时地生成访问的网页,展示给访问者,这样,内容可以随时变化,但是从数据库读多次把所需要的数据取出来,要比从内存或者硬盘等一次读出来 付出的成本大很多。而使用缓存的话,可以将数据保存在缓存中,下次访问的时候直接从缓存中获得数据,而不用去请求后端数据库,这样服务器可以很快的响应请求,从而提高加载速度。

缓存系统工作原理:

对于给定的网址,尝试从缓存中找到网址,如果页面在缓存中,直接返回缓存的页面,如果缓存中没有,一系列操作(比如查数据库)后,保存生成的页面内容到缓存系统以供下一次使用,然后返回生成的页面内容。

一般来说我们用 Django 来搭建一个网站,要用到数据库等。

from django.shortcuts import render
def index(request):
    # 读取数据库等 并渲染到网页
    # 数据库获取的结果保存到 queryset 中
    return render(request, 'index.html', {'queryset':queryset})

像这样每次访问都要读取数据库,一般的小网站没什么问题,当访问量非常大的时候,就会有很多次的数据库查询,肯定会造成访问速度变慢,服务器资源占用较多等问题。

from django.shortcuts import render
from django.views.decorators.cache import cache_page
 
@cache_page(60 * 15) # 秒数,这里指缓存 15 分钟,不直接写900是为了提高可读性
def index(request):
    # 读取数据库等 并渲染到网页
    return render(request, 'index.html', {'queryset':queryset})

当使用了cache后,访问情况变成了如下:

# 访问一个网址时, 尝试从 cache 中找有没有缓存内容
# 如果网页在缓存中显示缓存内容,否则生成访问的页面,保存在缓存中以便下次使用,显示缓存的页面。
given a URL, try finding that page in the cache
if the page is in the cache:
    return the cached page
else:
    generate the page
    save the generated page in the cache (for next time)
    return the generated page

Django settings 中 cache 默认为

{
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
    }
}

也就是默认利用本地的内存来当缓存,速度很快。当然可能出来内存不够用的情况,其它的一些内建可用的 Backends 有

'django.core.cache.backends.db.DatabaseCache'
'django.core.cache.backends.dummy.DummyCache'
'django.core.cache.backends.filebased.FileBasedCache'
'django.core.cache.backends.locmem.LocMemCache'
'django.core.cache.backends.memcached.MemcachedCache'
'django.core.cache.backends.memcached.PyLibMCCache'

在 github 上也有用 redis 做 Django的缓存系统的开源项目:https://github.com/niwibe/django-redis,有兴趣的可以看看哦!

下面我们就来介绍一下各种缓存的配置:

缓存配置

利用文件系统来缓存:

这个很简单,就是将数据缓存在指定的目录中。配置如下:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',
        'TIMEOUT': 600,
        'OPTIONS': {
            'MAX_ENTRIES': 1000
        }
    }
}

利用数据库来缓存:

利用命令创建相应的表:

$ python manage.py createcachetable my_cache_table

配置如下所示:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',
        'TIMEOUT': 600,
        'OPTIONS': {
            'MAX_ENTRIES': 2000
        }
    }
}

使用Memcache来缓存:

Memcached 是目前 Django 可用的最快的缓存,

但是memcache需要你的服务器支持,也就是说需要有Memcache服务,

Linux系统安装Memcached,首先要先安装libevent库。

$ sudo apt-get install libevent ibevent-dev         自动下载安装(Ubuntu/Debian)

$ yum install libevent libevent-devel                    自动下载安装(Redhat/Fedora/Centos)

接着使用命令安装Memcache服务:

Ubuntu/Debian

$ sudo apt-get install memcached

Redhat/Fedora/Centos

$ yum install memcached

然后需要pip安装Memcached的插件Python-mencached和pylibmc

$ pip install Python-mencached
$ pip install pylibmc

最后在setting.py配置:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
        'TIMEOUT': 600,
        'OPTIONS': {
            'MAX_ENTRIES': 2000
        }
    }
}

使用Local-memory来缓存:

这种缓存方式会将数据保存在服务器的内存中。

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake',
        'TIMEOUT': 600,
        'OPTIONS': {
            'MAX_ENTRIES': 2000
        }
    }
}

最推荐的缓存方式是Memcache或者Local-memory,要不就是文件缓存,最不推荐的是数据库缓存。

下面用一些实例来说明如何使用 Django 缓存系统

使用 Django 缓存系统

全站缓存

这种方式最简单最容易配置了,就是将你全站都做缓存,所有的页面都会缓存下来,配置方式: 在setting.pyMIDDLEWARE中添加:

MIDDLEWARE = [
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',
]

也就是将django.middleware.cache.UpdateCacheMiddlewaredjango.middleware.cache.FetchFromCacheMiddleware分别添加在django.middleware.common.CommonMiddleware的前面和后面,注意,顺序不能反过来。 这种方式清除缓存的话使用:

from django.core.cache import cache
cache.clear()

视图缓存

这种方式会指定要缓存的视图,只会缓存这个视图,

from django.views.decorators.cache import cache_page

@cache_page(60 * 15, key_prefix="site1")
def my_view(request):
    ...

cache_page的参数分别是缓存过期时间以及缓存key的前缀。 也可以在路由url.py中指定要缓存的页面:

from django.views.decorators.cache import cache_page

urlpatterns = [
    url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
    #也可以这样,如果你的视图是classbase的话:
    url(r'^$', cache_page(60 * 60 * 10, key_prefix="blogindex")(views.IndexView.as_view()), name='index'),
]

如果你的视图是class base的话,可以这样使用缓存:

from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from django.views.generic import ListView

@method_decorator(cache_page(60*60), name='dispatch')
class MyListView(ListView):
    # Your view code here.

视图缓存的清除方式:

在django中可以使用cache_page的方式来缓存视图,但是如何删除指定视图的缓存呢?在文档中没找到清除的方式,但是在Google的时候找到了解决方案,我自己本地测试可以使用,不确定将来的版本会不会无效,下面先介绍下解决办法:

核心功能是这些:

def expire_view_cache(path, servername, serverport, key_prefix=None):
    from django.http import HttpRequest
    from django.utils.cache import get_cache_key

    request = HttpRequest()
    request.META = {'SERVER_NAME': servername, 'SERVER_PORT': serverport}
    request.path = path

    key = get_cache_key(request, key_prefix=key_prefix, cache=cache)
    if key:
        if cache.get(key):
            cache.delete(key)
        return True
    return False

其实就是构造一个HttpRequest对象,然后调用Django内部的get_cache_key来获得缓存key。 调用方式:

#site也可以直接指定,也就是当前站点的domain name
from django.contrib.sites.models import Site
site = Site.objects.get_current().domain
#path为要删除的视图缓存的路径,key_prefix为使用cache_page时指定的key_prefix
expire_view_cache(path, servername=site, serverport=port, key_prefix='blogdetail')

模版缓存

当然,也可以直接在模版中使用缓存

{% load cache %}
{% cache 500 sidebar request.user.username %}
    .. sidebar for logged in user ..
{% endcache %}

参数分别是过期时间,缓存名,区分不同缓存的参数 模版缓存的删除方式就简单多了,以上面的配置为例:

from django.core.cache.utils import make_template_fragment_key
from django.core.cache import cache
username = self.request.user.username if self.request.user else ''
key = make_template_fragment_key('sidebar', [username])
cache.delete(key)

此文章同时同步到我的个人博客緣來來來 » Django配置缓存机制

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容

  • Web框架之Django: (1)简介: Django是一个由Python写成开源的重量级Web应用框架,采用MT...
    老肖阅读 3,053评论 0 18
  • 模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。软件设计中通常用耦合度和内聚...
    riverstation阅读 2,070评论 0 8
  • 关于Mongodb的全面总结 MongoDB的内部构造《MongoDB The Definitive Guide》...
    中v中阅读 31,928评论 2 89
  • 点我查看本文集的说明及目录。 本项目相关内容包括: 实现过程: CH10 创建一个在线学习平台 CH11 缓存内容...
    学以致用123阅读 782评论 0 2
  • 初识简书是在豆瓣阅读上订阅的一本叫做[想想]的短文集,同期还收藏了几册知乎周刊,内容已经忘干净了,模模糊糊记得很有...
    圈一个阅读 192评论 0 2