Django 3.0.2中get_cache_key生成不一致缓存键,视图缓存失效操作失败的问题求助
解决Django视图缓存失效时cache_header键不匹配的问题
问题分析
从你描述的情况来看,生成的cache_header键和Redis中现存的不匹配,核心原因是伪造的请求对象和实际请求的元数据不一致,同时存在reverse调用时参数传递错误的问题。Django生成缓存键时,会严格依赖请求的路径、主机信息、语言等细节,哪怕一点点差异都会导致哈希值完全不同。
具体修正步骤
1. 修正伪造请求的META字段
你当前设置的SERVER_NAME是反向解析的地址1.0.0.127.in-addr.arpa,这和实际请求的主机信息不符。需要改成和实际请求一致的主机名/IP,同时补充HTTP_HOST字段(Django的get_host()方法优先读取这个值,会直接影响缓存键生成)。
比如实际请求是127.0.0.1:8000,META应该这样设置:
request.META = { 'SERVER_NAME': '127.0.0.1', 'SERVER_PORT': '8000', # 注意这里是字符串类型,和实际请求保持一致 'HTTP_HOST': '127.0.0.1:8000', }
2. 修正函数的参数传递逻辑
你的视图get_segment_list接收的是关键字参数(appid和page),但当前函数里用reverse(view_name, kwargs=args),而参数args默认是列表,这会导致生成的请求路径错误,进而哈希值不匹配。
修改函数定义,把args改为kwargs,并调整reverse的调用方式,同时补充删除cache_header键的逻辑:
def expire_view_cache(view_name, kwargs={}, namespace=None, key_prefix=None): """ This function allows you to invalidate any view-level cache. view_name: view function you wish to invalidate or it's named url pattern kwargs: keyword arguments passed to the view function namespace: optional, if an application namespace is needed key prefix: for the @cache_page decorator for the function (if any) """ from django.urls import reverse from django.http import HttpRequest from django.utils.cache import get_cache_key from django.core.cache import cache # 创建伪造请求对象 request = HttpRequest() request.method = 'GET' # 显式设置请求方法,避免默认值问题 request.LANGUAGE_CODE = 'en-us' # 处理命名空间 if namespace: view_name = f"{namespace}:{view_name}" # 设置正确的主机元数据 request.META = { 'SERVER_NAME': '127.0.0.1', 'SERVER_PORT': '8000', 'HTTP_HOST': '127.0.0.1:8000', } # 生成正确的请求路径(使用关键字参数) request.path = reverse(view_name, kwargs=kwargs) # 获取缓存键并删除对应的cache_page和cache_header key = get_cache_key(request, method='GET', key_prefix=key_prefix) if key: # 删除页面缓存 cache.delete(key) # 构造并删除对应的header缓存键 header_key = key.replace('cache_page', 'cache_header').split('.GET')[0] + f".{request.LANGUAGE_CODE}.UTC" cache.delete(header_key) return True return False
3. 正确调用失效函数
调用时传入视图对应的关键字参数,比如:
expire_view_cache('get_segment_list', kwargs={'appid': 'your_app_id', 'page': '1'})
额外注意点
- 如果你的视图有查询参数(比如
?foo=bar),需要在伪造请求中补充QUERY_STRING字段:request.META['QUERY_STRING'] = 'foo=bar'。 - 确保
request.LANGUAGE_CODE和实际请求的语言一致(你的Redis键里是en-us,当前设置没问题)。 - 如果使用了自定义的
key_prefix,调用时要传入对应的key_prefix参数。
内容的提问来源于stack exchange,提问作者Azima
相关产品推荐
相关产品推荐

