# 4、Django缓存



### Django-Redis

### 安装

`pip install django-redis Django`

支持 Redis cache/session 后端的全功能组件。充当cache/session Django-Redis依赖于pyredis

### 作为session后端

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

### 作为cache后端

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

### **应用**

```python
MIDDLEWARE = [
    'django.middleware.cache.UpdateCacheMiddleware',  # 放在第一
    # 其他中间件...
    'django.middleware.cache.FetchFromCacheMiddleware',  # 放在最后
]
 
CACHE_MIDDLEWARE_ALIAS = ""          # 用于存储的缓存别名
CACHE_MIDDLEWARE_SECONDS = 600       # 每个页面应缓存的秒数 
CACHE_MIDDLEWARE_KEY_PREFIX = ""     # 如果使用相同的Django安装在多个站点之间共享缓存，请将其设置为站点名称或此Django实例特有的其他字符串，以防止发生密钥冲突。如果你不在乎，请使用空字符串。
```

### **单独视图缓存**

> （记得取消全站缓存中间件配置）

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

```python
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})
```

### **模板局部缓存**：

```python
# 1.引入TemplateTag
{% load cache %}
 
# 2.使用缓存
{% cache 600 name %}  # 第一个参数表示缓存时间，第二个参数是key值（取缓存的时候，需要根据key值取）
  缓存内容
{% endcache %}
```

### **在路由URLConf中使用cache**

前一节中的范例将视图硬编码为使用缓存，因为 cache\_page 在适当的位置对 my\_view 函数进行了转换。 该方法将视图与缓存系统进行了耦合，从几个方面来说并不理想。 例如，你可能想在某个无缓存的站点中重用该视图函数，或者你可能想将该视图发布给那些不想通过缓存使用它们的人。 解决这些问题的方法是在 URLconf 中指定视图缓存，而不是紧挨着这些视图函数本身来指定。 完成这项工作非常简单： 在 URLconf 中用到这些视图函数的时候简单地包裹一个 cache\_page 。以下是刚才用到过的 URLconf : 这是之前的URLconf：

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

# 修改后
from django.views.decorators.cache import cache_page
 
urlpatterns = ('',
    (r'^foo/(\d{1,2})/$', cache_page(my_view, 60 * 15)),
)
```



### 其他缓存方式

缓存参数：

* TIMEOUT: 缓存的默认超时时间，以秒为单位，默认300秒 || None（永不过期）|| 0 (立即过期)
* OPTIONS
  * MAX\_ENTRIES: 删除旧值之前允许缓存的最大条目。默认是 `300`
  * CULL\_FREQUENCY: 当达到 `MAX_ENTRIES` 时，被删除的条目的比例。实际比例是 `1 / CULL_FREQUENCY`，所以将 `CULL_FREQUENCY` 设置为 `2`，即当达到 `MAX_ENTRIES` 时将删除一半的条目。这个参数应该是一个整数，默认为 `3`。值为 `0` 意味着当达到 `MAX_ENTRIES` 时，整个缓存将被转储。在某些后端（特别是 `database` ），这使得缓存速度 _更_ 快，但代价是缓存未命中更多。
* KEY\_PREFIX: 一个自动包含在 Django 服务器使用的所有缓存键中的字符串（默认为前缀）
* VERSION ：Django 服务器生成的缓存键的默认版本号
* KEY\_FUNCTION : 一个字符串，包含一个函数的点分隔路径，该函数定义了如何将前缀、版本和键组成一个最终的缓存键。

#### Memcached 缓存实战

```python
pip install pymemcache 
```

```python
# setting.py
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
        'LOCATION': '127.0.0.1:11211',              # 单个 Memcached
        'KEY_FUNCTION': lambda key,prefix_key,version:"django:%s"%key   #自定义存储格式
        #'LOCATION': 'unix:/tmp/memcached.sock',     # 通过本地 Unix 套接字
        #'LOCATION': [                               # 多个 Memcached 
        #    '172.19.26.240:11211',
        #    '172.19.26.242:11211',
        #]
    }
}
```

**缺点**： 基于内存的缓存有一个缺点：因为缓存的数据存储在内存中，如果你的服务器崩溃，数据将丢失

#### REDIS 缓存实战

```python
MIDDLEWARE = [
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware', # 三项放在中间最上面
]


CACHE_MIDDLEWARE_SECONDS = 60  # default cache time for the whole website
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://redis:6379/1",
        # "LOCATION": "redis://password@redis:6379/1", # 方法一：Add Password 
        'TIMEOUT': 60, # default expire time per api call
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "SOCKET_CONNECT_TIMEOUT": 5,  # in seconds
            "SOCKET_TIMEOUT": 5,  # r/w timeout in seconds
            'MAX_ENTRIES': 10000,
            'KEY_PREFIX': 'recruit-',
            #'PASSWORD': 'password', #  方法二：Add Password 
        }
    }
}
```

#### **文件系统缓存实战**

```python
# 目录路径是绝对路径, 并且具有读写权限
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',
        #'LOCATION': 'c:/foo/bar',        # windows
    }
}
```

#### **本地内存缓存实战**

```python
# 适合开发
MIDDLEWARE = [
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware', # 三项放在中间最上面
]


CACHE_MIDDLEWARE_SECONDS = 60  # default cache time for the whole website
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake',
        'TIMEOUT': 60,
        'OPTIONS': {
            'MAX_ENTRIES': 10000,
            'KEY_PREFIX': 'recruit-',
        }
    }
}
```
