Metadata-Version: 1.0
Name: cache-tagging
Version: 0.7.5
Summary: Cache-tagging allows you easily invalidate all cache records tagged with a given tag(s). Django support.
Home-page: https://bitbucket.org/evotech/cache-tagging
Author: Ivan Zakrevsky
Author-email: ivzak@yandex.ru
License: BSD License
Description: ====================================
        Cache Tagging (with Django support)
        ====================================
        
        Cache tagging allows you easily invalidate all cache records tagged with a given tag(s). Django support.
        
        Tags are a way to categorize cache records.
        When you save a cache, you can set a list of tags to apply for this record.
        Then you will be able to invalidate all cache records tagged with a given tag (or tags).
        
        Forked from https://github.com/Harut/django-cachecontrol
        
        Some ideas from http://dklab.ru/lib/Dklab_Cache/
        
        Cache tagging allows to manage cached values and easily link them to Model signals.
        
        Usage with Django
        ==================
        
        project urls.py::
        
            from cache_tagging.django_cache_tagging import autodiscover
            autodiscover()
        
        application example 1::
        
            # Default backend
            from cache_tagging.django_cache_tagging import cache
        
            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)))
        
        application example 2::
        
            # Custom backend
            from cache_tagging.django_cache_tagging import get_cache
            cache = get_cache('my_backend')
        
            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)))
        
        manual invalidation::
        
            from cache_tagging.django_cache_tagging import cache
            
            # ...
            cache.invalidate_tags('tag1', 'tag2', 'tag3')
            # or
            tag_list = ['tag1', 'tag2', 'tag3', ]
            cache.invalidate_tags(*tag_list)
        
        appname.caches.py file::
            
            # 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.
            # Thanks to currying, inside the handler function is available all local variables from signal.
        
            from cache_tagging.django_cache_tagging import registry
            from models import Post
            from news import Article
        
            caches = [
                #((model, func, [cache_object, ])),
                ((Post, lambda obj: ("blog.post.pk:{0}".format(obj.pk), ), get_cache('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),  # Complex tag
                                        "news.alticle"))),
            ]
            registry.register(caches)
        
        
            # Variant 2. Low-lewel. Using signals for invalidation.
        
            from cache_tagging.django_cache_tagging import registry, get_cache
            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)
            post_delete.connect(invalidation_callback, sender=Post)
        
        template::
        
            {% 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 %}
        
        `django-phased <https://github.com/codysoyland/django-phased>`_ support::
        
            {% comment %}
                django-phased support https://github.com/codysoyland/django-phased
                See documentation for more details http://django-phased.readthedocs.org/
            {% 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 support::
        
            {% 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 %}
        
        view decorator::
        
            from cache_tagging.django_cache_tagging.decorators import cache_page
        
            # See also useful decorator to bind view's args and kwargs to request
            # https://bitbucket.org/evotech/django-ext/src/d8b55d86680e/django_ext/middleware/view_args_to_request.py
        
            @cache_page(3600, tags=lambda request: ('blog.post', ) + Article.get_tags_for_request(request))
            def cached_view(request):
                result = get_result()
                return HttpResponse(result)
        
        How about transaction and multithreading (multiprocessing)?::
        
            from django.db import transaction
            from cache_tagging.django_cache_tagging import cache
        
            cache.transaction_begin()
            with 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.
        
            cache.transaction_finish()  # Invalidates cache tags again, after transaction commit/rollback.
        
        Transaction handler as decorator::
        
            from django.db import transaction
            from cache_tagging.django_cache_tagging import cache
            from cache_tagging.django_cache_tagging.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 also invalidate cache before data changes,
                # by signals django.db.models.signals.pre_save()
                # or django.db.models.signals.pre_delete(), and do not worry.
        
        Transaction handler as middleware::
        
            MIDDLEWARE_CLASSES = [
                # ...
                "cache_tagging.django_cache_tagging.middleware.TransactionMiddleware",  # Should be before
                "django.middleware.transaction.TransactionMiddleware",
                # ...
            ]
        
Keywords: django cache tagging
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Software Development :: Libraries :: Python Modules
