# 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-',
        }
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://close.gitbook.io/yun-wei-bi-ji/python/django/4django-huan-cun.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
