Django - 缓存
Django - 缓存
Section titled “Django - 缓存”缓存(Caching)意味着存储一个耗时操作的结果,这样下次需要相同结果时就不必再次执行该操作。你可以将其类比为记住一道复杂数学题的答案,而不是每次有人问时都重新计算。
以下是缓存工作的一个简单概念:
给定一个请求(例如,请求一个特定的网页 URL):1. 检查缓存中是否存在针对此请求的有效、预先计算好的结果。2. 如果存在: - 直接返回缓存的结果。3. 如果不存在: - 执行耗时操作(例如,通过查询数据库、渲染模板来生成网页)。 - 将新生成的结果保存到缓存中,供将来请求使用。 - 返回生成的结果。Django 提供了一个强大的缓存框架,允许你缓存应用程序的各个部分以提高性能:
- 特定视图(view)的输出。
- 模板的部分内容(模板片段)。
- 整个网站。
- 使用底层 API 缓存任意耗时计算的结果。
要在 Django 中开始使用缓存,首先需要配置缓存数据存储的位置(即缓存后端,cache backend)。Django 支持多种后端:
- 数据库缓存(Database Caching): 将缓存数据存储在 Django 项目的数据库中。
- 文件系统缓存(Filesystem Caching): 将缓存数据存储为服务器上的独立文件。
- 内存缓存(LocMem): 将缓存数据存储在 Web 服务器进程的内存中。速度非常快,但在不同进程之间不共享。
- Memcached: 使用快速的、外部的内存缓存服务器(Memcached)。需要安装 Memcached 服务器和相应的 Python 库(例如
pylibmc或pymemcache)。 - Redis: 使用快速的、外部内存数据结构存储系统(Redis)。需要安装 Redis 服务器和相应的 Python 库(例如
redis或django-redis)。
你在项目的 settings.py 文件中使用 CACHES 设置来配置缓存后端。
设置数据库缓存
Section titled “设置数据库缓存”将以下内容添加到你的 settings.py 文件中:
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.db.DatabaseCache', 'LOCATION': 'my_cache_table', # Choose a name for your cache table # 选择一个你的缓存表名 }}配置完成后,你需要运行以下命令在数据库中创建缓存表:
python manage.py createcachetable设置文件系统缓存
Section titled “设置文件系统缓存”将以下内容添加到你的 settings.py 文件中:
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', 'LOCATION': '/var/tmp/django_cache', # Ensure this directory exists and is writable by the web server # 确保此目录存在并且 Web 服务器有写入权限 }}设置 Memcached 缓存
Section titled “设置 Memcached 缓存”这通常是生产环境中最具性能的选项。首先,安装一个 Memcached 客户端库(例如 pymemcache):pip install pymemcache。然后,配置 settings.py:
# Using pymemcache client# 使用 pymemcache 客户端CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache', 'LOCATION': '127.0.0.1:11211', # Assumes Memcached is running on localhost, port 11211 # 假设 Memcached 运行在 localhost 的 11211 端口 }}
# Or using a Unix socket# 或者使用 Unix 套接字# CACHES = {# 'default': {# 'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',# 'LOCATION': 'unix:/tmp/memcached.sock',# }# }设置 Redis 缓存
Section titled “设置 Redis 缓存”Redis 是另一个高性能缓存的优秀选择。首先,安装一个 Redis 客户端库和一个适用于 Django 的 Redis 缓存后端(例如 django-redis):pip install django-redis redis。然后,配置 settings.py:
CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/1", # Assumes Redis is running on localhost, port 6379, using DB 1 # 假设 Redis 运行在 localhost 的 6379 端口,使用 DB 1 "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", } }}有关更多配置选项,请参阅 django-redis 文档。
缓存整个网站
Section titled “缓存整个网站”使用缓存最简单的方法是缓存整个网站。这通过将 Django 的缓存中间件添加到 settings.py 中的 MIDDLEWARE 设置来完成。顺序至关重要:
MIDDLEWARE = [ # ... other middleware ... # ... 其他中间件 ... 'django.middleware.cache.UpdateCacheMiddleware', # Must be first or near the start # 必须在最前面或靠近开始的地方 'django.middleware.common.CommonMiddleware', # ... other middleware ... # ... 其他中间件 ... 'django.middleware.cache.FetchFromCacheMiddleware', # Must be last or near the end # 必须在最后面或靠近结束的地方 # ... other middleware ... # ... 其他中间件 ...]解释:UpdateCacheMiddleware 需要在生成响应 之后 运行才能缓存它。FetchFromCacheMiddleware 需要在其他中间件 之前 运行,以便查看是否可以直接从缓存中提供请求。
然后,在 settings.py 中配置这些设置:
# The cache alias defined in CACHES to use for storage.# 在 CACHES 中定义的用于存储的缓存别名。CACHE_MIDDLEWARE_ALIAS = 'default'
# The default number of seconds each page should be cached.# 每个页面默认应缓存的秒数。CACHE_MIDDLEWARE_SECONDS = 600 # Cache for 10 minutes# 缓存 10 分钟
# Optional: A prefix for cache keys generated by the middleware.# 可选:中间件生成的缓存键的前缀。CACHE_MIDDLEWARE_KEY_PREFIX = ''全站缓存对于静态内容较多的网站有效,但对于高度动态的网站则不太有用。
为了实现更细粒度的控制,你可以使用 cache_page 装饰器缓存单个视图的输出。将其直接应用于你的视图函数:
from django.views.decorators.cache import cache_pagefrom django.http import HttpResponseimport datetime
# Cache this view for 15 minutes (900 seconds)# 缓存此视图 15 分钟 (900 秒)@cache_page(60 * 15)def expensive_calculation_view(request): # Simulate an expensive operation # 模拟一个耗时操作 now = datetime.datetime.now() html = f"<html><body>It is now {now}.</body></html>" return HttpResponse(html)
# Example view with parameters# 带参数的示例视图@cache_page(60 * 15)def view_articles_by_month(request, year, month): text = f"Displaying articles for month: {month}/{year}" # In a real app, you'd query the database here # 在实际应用中,你会在 GITHUB 此处查询数据库 return HttpResponse(text)cache_page 装饰器将其参数设置为缓存超时时间,单位为秒。每个唯一的 URL 都将独立缓存。例如,对 /articles/02/2023/ 的请求将独立于对 /articles/03/2024/ 的请求进行缓存。
你还可以在 URL 配置(urls.py)中应用 cache_page,这在不修改视图代码的情况下应用缓存时很有用:
from django.urls import path, re_pathfrom django.views.decorators.cache import cache_pagefrom . import views # Assuming views are in the same app's views.py# 假设视图位于同一应用的 views.py 中
urlpatterns = [ # Cache the view for 15 minutes directly in the URLconf # 直接在 URLconf 中缓存视图 15 分钟 re_path( r'^articles/(?P<month>\d{2})/(?P<year>\d{4})/$', cache_page(60 * 15)(views.view_articles_by_month), name='articles_by_month' ), path('expensive/', views.expensive_calculation_view, name='expensive_view'),]如果在 urls.py 中应用了缓存,那么对于该特定视图,你就不需要在 views.py 中使用 @cache_page 装饰器了。
缓存模板片段
Section titled “缓存模板片段”有时,页面中只有一部分计算量较大或变化不频繁。你可以使用 {% cache %} 模板标签在模板内缓存这些特定部分。
考虑以下模板片段:
{% extends "base.html" %}{% load cache %}
{% block title %}My Page Title{% endblock %}{% block title %}我的页面标题{% endblock %}
{% block content %} <h1>Welcome, {{ user.username }}!</h1> <h1>欢迎,{{ user.username }}!</h1>
{# This part is expensive to generate #} {# 这部分生成成本较高 #} {% cache 3600 sidebar request.user.username %} {# Cache for 1 hour, vary by username #} {# 缓存 1 小时,根据用户名变化 #} <div class="sidebar"> <h2>Recommendations for You</h2> <h2>为您推荐</h2> <ul> {% for item in recommended_items %} <li>{{ item.name }}</li> {% empty %} <li>No recommendations available.</li> <li>暂无推荐。</li> {% endfor %} </ul> </div> {% endcache %}
<div class="main-content"> <p>This content changes frequently.</p> <p>此内容经常变化。</p> <p>Current time: {% now "H:i:s" %}</p> <p>当前时间:{% now "H:i:s" %}</p> </div>{% endblock %}解释:
- 首先,加载缓存库:
{% load cache %}。 {% cache %}标签至少接受两个参数:以秒为单位的缓存超时时间(例如3600)和缓存片段的唯一名称(例如sidebar)。- 你可以选择添加更多参数(如上面的
request.user.username),以便根据这些值创建不同的缓存版本。这称为缓存的“变化”(varying)。 {% cache %}和{% endcache %}之间的所有内容都将被缓存。
底层缓存 API
Section titled “底层缓存 API”要缓存任意 Python 对象或在视图/模板上下文之外的函数结果,可以使用底层缓存 API:
from django.core.cache import cacheimport time
def get_complex_data(user_id): cache_key = f'complex_data_{user_id}' result = cache.get(cache_key)
if result is None: # Data not in cache, calculate it # 数据不在缓存中,计算它 print(f'Calculating complex data for user {user_id}...') # 模拟耗时操作 time.sleep(2) # Simulate expensive operation result = {'data': f'Some complex data for {user_id}', 'timestamp': time.time()}
# Store in cache for 5 minutes (300 seconds) # 存储到缓存中 5 分钟 (300 秒) cache.set(cache_key, result, 300) print('Data stored in cache.') print('数据已存入缓存。') else: print(f'Retrieved complex data for user {user_id} from cache.') print(f'从缓存中检索到用户 {user_id} 的复杂数据。')
return result
# Example usage# 示例用法data1 = get_complex_data(123)data2 = get_complex_data(123) # This call should hit the cache# 此调用应该命中缓存主要方法包括 cache.set(key, value, timeout)、cache.get(key, default=None)、cache.delete(key)、cache.clear() 等等。请参阅 Django 文档以获取完整的 API 说明。
延伸阅读:
- Django 缓存框架文档:https://docs.djangoproject.com/en/stable/topics/cache/