缓存依赖项(以前的缓存标记)允许您轻松地使用给定标记标记的所有缓存记录失效。支持Django。
cache-dependencies的Python项目详细描述
缓存依赖项(以前的缓存标记)允许您轻松地使用给定标记标记的所有缓存记录失效。支持Django。
标记是对缓存记录进行分类的一种方法。 保存缓存时,可以设置要应用于此记录的标记列表。 然后,您将能够使使用给定标记(或多个标记)标记的所有缓存记录失效。
缓存标记允许管理缓存值并轻松将其链接到模型信号。
- 主页:https://bitbucket.org/emacsway/cache-dependencies
- 文件:https://cache-dependencies.readthedocs.io/
- 浏览源代码(规范回购):https://bitbucket.org/emacsway/cache-dependencies/src
- Github镜像:https://github.com/emacsway/cache-dependencies
- 获取源代码(规范回购):hg clone https://bitbucket.org/emacsway/cache-dependencies
- 获取源代码(镜像):git clone https://github.com/emacsway/cache-dependencies.git
- 圆周率:https://pypi.python.org/pypi/cache-dependencies
许可证:
- 许可证是BSD
与django一起使用
项目设置.py:
INSTALLED_APPS = ( # ... 'django_cache_dependencies', # ... )
项目URL.py:
from django_cache_dependencies import autodiscover autodiscover()
应用示例:
# Default backend from django_cache_dependencies import caches cache = caches['default'] value = cache.get('cache_name') if value is None: value = get_value_func() cache.set('cache_name', value, tags=( 'blog.post', 'categories.category.pk:{0}'.format(obj.category_id), ))
手动失效:
from django_cache_dependencies import caches cache = caches['default'] # ... cache.invalidate_tags('tag1', 'tag2', 'tag3') # or tag_list = ['tag1', 'tag2', 'tag3', ] cache.invalidate_tags(*tag_list)
祖先自动从其后代接收标记。 您不必担心如何从片段的缓存中传递标记 到复合(父)缓存。自动完成:
val1 = cache.get('name1') if val1 is None: val2 = cache.get('name2') if val2 is None: val2 = get_val2() cache.set('name2', val2, ('tag2', ), 120) val1 = get_val1() + val2 cache.set('name1', val1, ('tag1', ), 120) cache.invalidate_tags('tag2') assert cache.get('name2') is None assert cache.get('name1') is None # cache with name 'name1' was invalidated # by tag 'tag2' of descendant.
您可以关闭此逻辑:
# turn off for cache instance cache.ignore_descendants = True # turn off for get template cache.get('cachename', abort=True) # abort cache creating val = cache.get('cachename') if val is None: try: val = get_val() except Exception: cache.abort('cachename')
appname.caches.py文件:
# Variant 1. Using registry.register(). # Each item from list creates model's post_save and pre_delete signal. # Func takes changed model and returns list of tags. # When the signal is called, it gets varied tags and deletes all caches with this tags. # Inside the handler function available all local variables from signal. # Or only object. Of your choice. from django_cache_dependencies import registry, caches from models import Post from news import Article cache_handlers = [ #(model, func, [cache_alias, ]), (Post, lambda *a, **kw: ("blog.post.pk:{0}".format(kw['instance'].pk), ), 'my_cache_alias'), (Article, lambda obj: ( "news.alticle.pk:{0}".format(obj.pk), "categories.category.pk:{0}.blog.type.pk:{1}".format(obj.category_id, obj.type_id), # Composite tag "news.alticle" )), ] registry.register(cache_handlers) # Variant 2. Low-lewel. Using signals for invalidation. from django_cache_dependencies import registry from models import Post from django.db.models.signals import post_save, post_delete def invalidation_callback(sender, instance, **kwars): cache.invalidate_tags( 'tag1', 'tag2', 'blog.post.pk:{1}'.format(instance.pk) ) post_save.connect(invalidation_callback, sender=Post) pre_delete.connect(invalidation_callback, sender=Post)
模板:
{% load cache_tagging_tags %} {% cache_tagging 'cache_name' 'categories.category.pk:15' 'blog.post' tags=tag_list_from_view timeout=3600 %} ... {% cache_add_tags 'new_tag1' %} ... {% cache_add_tags 'new_tag2' 'new_tag3' %} ... {% if do_not_cache_condition %} {% cache_tagging_prevent %} {% endif %} {% end_cache_tagging %} {% comment %} {% cache_tagging cache_name [tag1] [tag2] ... [tags=tag_list] [timeout=3600] %} {% cache_add_tags tag_or_list_of_tags %} If context has attribute "request", then templatetag {% cache_tagging %} adds to request a new attribute "cache_tagging" (instance of set() object) with all tags. If request already has attribute "cache_tagging", and it's instance of set() object, then templatetag {% cache_tagging %} adds all tags to this object. You can use together templatetag {% cache_tagging %} and decorator @cache_page(). In this case, when @cache_page() decorator will save response, it will also adds all tags from request.cache_tagging to cache. You need not worry about it. If need, you can prevent caching by templatetag {% cache_tagging_prevent %}. In this case also will be prevented @cache_page() decorator, if it's used, and context has attribute "request". {% endcomment %}
{% comment %} Support for django-phased https://github.com/codysoyland/django-phased See documentation for more details https://django-phased.readthedocs.io/ {% endcomment %} {% load cache_tagging_tags %} {% load phased_tags %} {% cache_tagging 'cache_name' 'categories.category.pk:15' 'blog.post' tags=tag_list_from_view timeout=3600 phased=1 %} ... Cached fragment here ... {% phased with comment_count object %} {# Non-cached fragment here. #} There are {{ comment_count }} comments for "{{ object }}". {% endphased %} {% end_cache_tagging %}
nocache支持:
{% load cache_tagging_tags %} {% cache_tagging 'cache_name' 'categories.category.pk:15' 'blog.post' tags=tag_list_from_view timeout=3600 nocache=1 %} ... Cached fragment here ... {% nocache %} """ Non-cached fragment here. Just python code. Why nocache, if exists django-phased? Because template engine agnostic. We can use not only Django templates. Of course, for only Django template engine, django-phased is the best option. """ if request.user.is_authenticated(): echo('Hi, ', filters.escape(request.user.username), '!') echo(render_to_string('user_menu.html', context)) else: echo(render_to_string('login_menu.html', context)) {% endnocache %} {% end_cache_tagging %}
视图装饰器:
from django_cache_dependencies.decorators import cache_page # See also useful decorator to bind view's args and kwargs to request # https://bitbucket.org/emacsway/django-ext/src/d8b55d86680e/django_ext/middleware/view_args_to_request.py @cache_page(3600, tags=lambda request: ('blog.post', ) + get_tags_for_request(request)) def cached_view(request): result = get_result() return HttpResponse(result)
事务和多线程(多处理)怎么样?:
from django.db import transaction from django_cache_dependencies import cache from django_cache_dependencies import cache_transaction with cache.transaction, transaction.commit_on_success(): # ... some code # Changes a some data cache.invalidate_tags('tag1', 'tag2', 'tag3') # ... some long code # Another concurrent process/thread can obtain old data at this time, # after changes but before commit, and create cache with old data, # if isolation level is not "Read uncommitted". # Otherwise, if isolation level is "Read uncommitted", and transaction will rollback, # the concurrent and current process/thread can creates cache with dirty data.
作为装饰器的事务处理程序:
from django.db import transaction from django_cache_dependencies import cache from django_cache_dependencies.decorators import cache_transaction @cache.transaction @transaction.commit_on_success(): def some_view(request): # ... some code cache.invalidate_tags('tag1', 'tag2', 'tag3') # ... some long code # Another concurrent process/thread can obtain old data at this time, # after changes but before commit, and create cache with old data, # if isolation level is not "Read uncommitted". # Otherwise, if isolation level is "Read uncommitted", and transaction will rollback, # the concurrent and current process/thread can creates cache with dirty data. # # We can even invalidate cache before data changes, # by signals django.db.models.signals.pre_save() # or django.db.models.signals.pre_delete(), and don't worry.
作为中间件的事务处理程序:
MIDDLEWARE_CLASSES = [ # ... "django_cache_dependencies.middleware.TransactionMiddleware", # Should be before "django.middleware.transaction.TransactionMiddleware", # ... ]
从https://github.com/Harut/django-cachecontrol分叉
另请参阅文章: