我想根据发送给它的POST数据来缓存一些视图。
django.views.decorators.cache.cache_page
装饰器会自动执行此操作,还是需要以某种方式对其进行调整?在后一种情况下,我该怎么办?
我正在尝试缓存GraphQL POST请求。
答案 0 :(得分:3)
否,永远不会缓存POST响应:
if request.method not in ('GET', 'HEAD'):
request._cache_update_cache = False
return None # Don't bother checking the cache.
(来自django.middleware.cache中的FetchFromCacheMiddleware
)。
您必须使用low-level cache API自己实现一些功能。缓存对POST请求的响应是最不寻常的,因为POST请求是要更改数据库中的内容,并且结果对于特定请求而言总是始终唯一。您必须考虑到底要缓存什么。
答案 1 :(得分:1)
我最终创建了一个自定义装饰器,该装饰器根据请求路径,查询参数和发布的数据来缓存响应:
# myproject/apps/core/caching.py
import hashlib
import base64
from functools import wraps
from django.core.cache import cache
from django.conf import settings
def make_hash_sha256(o):
hasher = hashlib.sha256()
hasher.update(repr(make_hashable(o)).encode())
return base64.b64encode(hasher.digest()).decode()
def make_hashable(o):
if isinstance(o, (tuple, list)):
return tuple((make_hashable(e) for e in o))
if isinstance(o, dict):
return tuple(sorted((k,make_hashable(v)) for k,v in o.items()))
if isinstance(o, (set, frozenset)):
return tuple(sorted(make_hashable(e) for e in o))
return o
def cache_get_and_post_requests(duration=600):
def view_decorator(view):
@wraps(view)
def view_wrapper(request, *args, **kwargs):
# TODO: make the key also dependable on the user or cookies if necessary
cache_key = "-".join((
settings.CACHE_MIDDLEWARE_KEY_PREFIX,
make_hash_sha256((
request.path,
list(request.GET.items()),
list(request.POST.items()),
request.body,
)),
))
cached_response = cache.get(cache_key)
if cached_response:
return cached_response
response = view(request, *args, **kwargs)
cache.set(cache_key, response, duration)
return response
return view_wrapper
return view_decorator
然后我可以像这样在URL配置中使用它:
# myproject/urls.py
from django.urls import path
from django.conf.urls.i18n import i18n_patterns
from graphene_django.views import GraphQLView
from myproject.apps.core.caching import cache_get_and_post_requests
urlpatterns = i18n_patterns(
# …
path("graphql/", cache_get_and_post_requests(60*5)(GraphQLView.as_view(graphiql=True))),
)