| 作者 | 一个基于GAE memcache的Django cache middleware实现 |
|
Chris1919 2009-03-22 12:57 |
Django自带的cache framework没法直接在GAE上工作,大概要做一个custom cache backend,而我又不爱用app-engine-patch这样的东西。另外,Django cache framework有个方面没法满足我的需求,我希望网站有更新后,相关cache能够自动失效。于是自己写了个简单的cache middleware。
from google.appengine.api import users
from google.appengine.api import memcache
class CacheMiddleware(object):
"""
This is a very simple middleware that add cache functionality
"""
def process_request(self, request):
request._cache_update_cache = False
#only use cache for anonymous user
if users.get_current_user():
return None
if request.method != 'GET':
return None
key = request.get_full_path()
try:
response = memcache.get(key)
if response is not None:
return response
except:
pass
request._cache_update_cache = True
return None
def process_response(self, request, response):
if request.method == 'POST':
memcache.flush_all()
"Sets the cache, if needed."
if not hasattr(request, '_cache_update_cache') or not request._cache_update_cache:
# We don't need to update the cache, just return.
return response
if request.method != 'GET':
return response
if not response.status_code == 200:
return response
key = request.get_full_path()
try:
memcache.set(key, response)
except:
pass
return response
这个cache middleware只对匿名用户进行缓存。而且每当有POST请求后自动flush_all(flush_all本身的效率很好,时间复杂度为O(1)),这样会影响cache的命中率,不过对于不太频繁更新的站点来讲,这个影响很小。由于有时候也需要对登录用户进行缓存,就写了个cache decorator,来处理对于特殊的view的缓存。 from google.appengine.api import users
from google.appengine.api import memcache
KEY_PAGE = 'PAGE_'
COMMON_TIME_OUT = 3600
def check_page_cache(always=False):
def decorator(method):
def new_method(request, *args, **kwds):
#only use cache for anonymous user
if users.get_current_user() and not always:
return method(request, *args, **kwds)
if request.method != 'GET':
return method(request, *args, **kwds)
key = KEY_PAGE + request.get_full_path()
#try to fetch data from cache
try:
response = memcache.get(key)
except:
response = None
if response is not None:
return response
response = method(request, *args, **kwds)
#only cache valid response
if not response.status_code == 200:
return response
#try to fill data to cache
try:
memcache.set(key, response)
finally:
return response
return new_method
return decorator
使用方法:
@check_page_cache(True)
view_function(request, ...)
#your logic...
|