{ "info": { "author": "Ivan Zakrevsky", "author_email": "ivzak@yandex.ru", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "============================================\nCache Dependencies (with support for Django)\n============================================\n\nCache-dependencies (former Cache-tagging) allows you easily invalidate all cache records tagged with a given tag(s). Supports Django.\n\nTags are a way to categorize cache records.\nWhen you save a cache, you can set a list of tags to apply for this record.\nThen you will be able to invalidate all cache records tagged with a given tag (or tags).\n\nCache tagging allows to manage cached values and easily link them to Model signals.\n\n* Home Page: https://bitbucket.org/emacsway/cache-dependencies\n* Docs: https://cache-dependencies.readthedocs.io/\n* Browse source code (canonical repo): https://bitbucket.org/emacsway/cache-dependencies/src\n* GitHub mirror: https://github.com/emacsway/cache-dependencies\n* Get source code (canonical repo): ``hg clone https://bitbucket.org/emacsway/cache-dependencies``\n* Get source code (mirror): ``git clone https://github.com/emacsway/cache-dependencies.git``\n* PyPI: https://pypi.python.org/pypi/cache-dependencies\n\nLICENSE:\n\n* License is BSD\n\n\nUsage with Django\n==================\n\nproject settings.py::\n\n INSTALLED_APPS = (\n # ...\n 'django_cache_dependencies',\n # ...\n )\n\nproject urls.py::\n\n from django_cache_dependencies import autodiscover\n autodiscover()\n\napplication example::\n\n # Default backend\n from django_cache_dependencies import caches\n cache = caches['default']\n\n value = cache.get('cache_name')\n if value is None:\n value = get_value_func()\n cache.set('cache_name', value, tags=(\n 'blog.post',\n 'categories.category.pk:{0}'.format(obj.category_id),\n ))\n\nmanual invalidation::\n\n from django_cache_dependencies import caches\n cache = caches['default']\n\n # ...\n cache.invalidate_tags('tag1', 'tag2', 'tag3')\n # or\n tag_list = ['tag1', 'tag2', 'tag3', ]\n cache.invalidate_tags(*tag_list)\n\nAncestors automatically receive tags from their descendants.\nYou do not have to worry about how to pass the tags from fragment's caches\nto the composite (parent) cache. It is done automatically::\n\n val1 = cache.get('name1')\n\n if val1 is None:\n val2 = cache.get('name2')\n\n if val2 is None:\n val2 = get_val2()\n cache.set('name2', val2, ('tag2', ), 120)\n\n val1 = get_val1() + val2\n cache.set('name1', val1, ('tag1', ), 120)\n\n cache.invalidate_tags('tag2')\n assert cache.get('name2') is None\n assert cache.get('name1') is None # cache with name 'name1' was invalidated\n # by tag 'tag2' of descendant.\n\n\nYou can turn off this logic::\n\n # turn off for cache instance\n cache.ignore_descendants = True\n\n # turn off for get template\n cache.get('cachename', abort=True)\n\n # abort cache creating\n val = cache.get('cachename')\n if val is None:\n try:\n val = get_val()\n except Exception:\n cache.abort('cachename')\n\nappname.caches.py file::\n \n # Variant 1. Using registry.register().\n # Each item from list creates model's post_save and pre_delete signal.\n # Func takes changed model and returns list of tags.\n # When the signal is called, it gets varied tags and deletes all caches with this tags.\n # Inside the handler function available all local variables from signal.\n # Or only object. Of your choice.\n\n from django_cache_dependencies import registry, caches\n from models import Post\n from news import Article\n\n cache_handlers = [\n #(model, func, [cache_alias, ]),\n (Post, lambda *a, **kw: (\"blog.post.pk:{0}\".format(kw['instance'].pk), ), 'my_cache_alias'),\n (Article, lambda obj: (\n \"news.alticle.pk:{0}\".format(obj.pk),\n \"categories.category.pk:{0}.blog.type.pk:{1}\".format(obj.category_id, obj.type_id), # Composite tag\n \"news.alticle\"\n )),\n ]\n registry.register(cache_handlers)\n\n\n # Variant 2. Low-lewel. Using signals for invalidation.\n\n from django_cache_dependencies import registry\n from models import Post\n from django.db.models.signals import post_save, post_delete\n\n def invalidation_callback(sender, instance, **kwars):\n cache.invalidate_tags(\n 'tag1', 'tag2', 'blog.post.pk:{1}'.format(instance.pk)\n )\n\n post_save.connect(invalidation_callback, sender=Post)\n pre_delete.connect(invalidation_callback, sender=Post)\n\ntemplate::\n\n {% load cache_tagging_tags %}\n {% cache_tagging 'cache_name' 'categories.category.pk:15' 'blog.post' tags=tag_list_from_view timeout=3600 %}\n ...\n {% cache_add_tags 'new_tag1' %}\n ...\n {% cache_add_tags 'new_tag2' 'new_tag3' %}\n ...\n {% if do_not_cache_condition %}\n {% cache_tagging_prevent %}\n {% endif %}\n {% end_cache_tagging %}\n {% comment %}\n {% cache_tagging cache_name [tag1] [tag2] ... [tags=tag_list] [timeout=3600] %}\n {% cache_add_tags tag_or_list_of_tags %}\n If context has attribute \"request\", then templatetag {% cache_tagging %}\n adds to request a new attribute \"cache_tagging\" (instance of set() object) with all tags.\n If request already has attribute \"cache_tagging\", and it's instance of set() object,\n then templatetag {% cache_tagging %} adds all tags to this object.\n You can use together templatetag {% cache_tagging %} and decorator @cache_page().\n In this case, when @cache_page() decorator will save response,\n it will also adds all tags from request.cache_tagging to cache.\n You need not worry about it.\n\n If need, you can prevent caching by templatetag {% cache_tagging_prevent %}.\n In this case also will be prevented @cache_page() decorator, if it's used,\n and context has attribute \"request\".\n {% endcomment %}\n\nSupport for `django-phased `_::\n\n {% comment %}\n Support for django-phased https://github.com/codysoyland/django-phased\n See documentation for more details https://django-phased.readthedocs.io/\n {% endcomment %}\n {% load cache_tagging_tags %}\n {% load phased_tags %}\n {% cache_tagging 'cache_name' 'categories.category.pk:15' 'blog.post' tags=tag_list_from_view timeout=3600 phased=1 %}\n ... Cached fragment here ...\n {% phased with comment_count object %}\n {# Non-cached fragment here. #}\n There are {{ comment_count }} comments for \"{{ object }}\".\n {% endphased %}\n {% end_cache_tagging %}\n\nnocache support::\n\n {% load cache_tagging_tags %}\n {% cache_tagging 'cache_name' 'categories.category.pk:15' 'blog.post' tags=tag_list_from_view timeout=3600 nocache=1 %}\n ... Cached fragment here ...\n {% nocache %}\n \"\"\"\n Non-cached fragment here. Just python code.\n Why nocache, if exists django-phased?\n Because template engine agnostic. We can use not only Django templates.\n Of course, for only Django template engine, django-phased is the best option.\n \"\"\"\n if request.user.is_authenticated():\n echo('Hi, ', filters.escape(request.user.username), '!')\n echo(render_to_string('user_menu.html', context))\n else:\n echo(render_to_string('login_menu.html', context))\n {% endnocache %}\n {% end_cache_tagging %}\n\nview decorator::\n\n from django_cache_dependencies.decorators import cache_page\n\n # See also useful decorator to bind view's args and kwargs to request\n # https://bitbucket.org/emacsway/django-ext/src/d8b55d86680e/django_ext/middleware/view_args_to_request.py\n\n @cache_page(3600, tags=lambda request: ('blog.post', ) + get_tags_for_request(request))\n def cached_view(request):\n result = get_result()\n return HttpResponse(result)\n\nHow about transaction and multithreading (multiprocessing)?::\n\n from django.db import transaction\n from django_cache_dependencies import cache\n from django_cache_dependencies import cache_transaction\n\n with cache.transaction, transaction.commit_on_success():\n # ... some code\n # Changes a some data\n cache.invalidate_tags('tag1', 'tag2', 'tag3')\n # ... some long code\n # Another concurrent process/thread can obtain old data at this time,\n # after changes but before commit, and create cache with old data,\n # if isolation level is not \"Read uncommitted\".\n # Otherwise, if isolation level is \"Read uncommitted\", and transaction will rollback,\n # the concurrent and current process/thread can creates cache with dirty data.\n\nTransaction handler as decorator::\n\n from django.db import transaction\n from django_cache_dependencies import cache\n from django_cache_dependencies.decorators import cache_transaction\n\n @cache.transaction\n @transaction.commit_on_success():\n def some_view(request):\n # ... some code\n cache.invalidate_tags('tag1', 'tag2', 'tag3')\n # ... some long code\n # Another concurrent process/thread can obtain old data at this time,\n # after changes but before commit, and create cache with old data,\n # if isolation level is not \"Read uncommitted\".\n # Otherwise, if isolation level is \"Read uncommitted\", and transaction will rollback,\n # the concurrent and current process/thread can creates cache with dirty data.\n #\n # We can even invalidate cache before data changes,\n # by signals django.db.models.signals.pre_save()\n # or django.db.models.signals.pre_delete(), and don't worry.\n\nTransaction handler as middleware::\n\n MIDDLEWARE_CLASSES = [\n # ...\n \"django_cache_dependencies.middleware.TransactionMiddleware\", # Should be before\n \"django.middleware.transaction.TransactionMiddleware\",\n # ...\n ]\n\nForked from https://github.com/Harut/django-cachecontrol\n\nSee also articles:\n\n- \"`About problems of cache invalidation. Cache tagging. `_\"\n- \"`\u041e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u0445 \u0438\u043d\u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u043a\u044d\u0448\u0430. \u0422\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u044d\u0448\u0430. `_\"\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://bitbucket.org/emacsway/cache-dependencies", "keywords": "django cache dependencies tagging", "license": "BSD License", "maintainer": "", "maintainer_email": "", "name": "cache-dependencies", "package_url": "https://pypi.org/project/cache-dependencies/", "platform": "", "project_url": "https://pypi.org/project/cache-dependencies/", "project_urls": { "Homepage": "https://bitbucket.org/emacsway/cache-dependencies" }, "release_url": "https://pypi.org/project/cache-dependencies/0.7.7.48/", "requires_dist": null, "requires_python": "", "summary": "Cache-dependencies (former Cache-tagging) allows you easily invalidate all cache records tagged with a given tag(s). Supports Django.", "version": "0.7.7.48" }, "last_serial": 3276409, "releases": { "0.7.7.39": [ { "comment_text": "", "digests": { "md5": "dac845ff4aa83f9387ccbc7cc36156cd", "sha256": "cd8b408d8040a86fcc77f38b44e486e2d519b63747c060b250d85e22a197104e" }, "downloads": -1, "filename": "cache-dependencies-0.7.7.39.tar.gz", "has_sig": false, "md5_digest": "dac845ff4aa83f9387ccbc7cc36156cd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 42978, "upload_time": "2016-12-12T21:29:12", "url": "https://files.pythonhosted.org/packages/e9/07/55b195760cdfe34758a4b004baca9a75f38a2b0ac0a507d30294c1155da4/cache-dependencies-0.7.7.39.tar.gz" } ], "0.7.7.40": [ { "comment_text": "", "digests": { "md5": "686354cbca388beb13b0d96218a5d5e3", "sha256": "52c862bc2dd5141fc9349f58017a8b17ec87d1839bddc6637cd54f5bde9b6761" }, "downloads": -1, "filename": "cache-dependencies-0.7.7.40.tar.gz", "has_sig": false, "md5_digest": "686354cbca388beb13b0d96218a5d5e3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 43005, "upload_time": "2016-12-12T22:34:24", "url": "https://files.pythonhosted.org/packages/11/cb/62069f31ac2bc1c340e347834674eb1d3412002517070571b98b094b44bf/cache-dependencies-0.7.7.40.tar.gz" } ], "0.7.7.41": [ { "comment_text": "", "digests": { "md5": "87cb383c91d678a427129c6f21a5c8ff", "sha256": "07beb1fbf7e1dbffc0e2142f8568212dc6d4569a07adaa9cdb571b7db10d8e50" }, "downloads": -1, "filename": "cache-dependencies-0.7.7.41.tar.gz", "has_sig": false, "md5_digest": "87cb383c91d678a427129c6f21a5c8ff", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 43007, "upload_time": "2016-12-13T02:31:43", "url": "https://files.pythonhosted.org/packages/94/2a/e800164f5f8f90a0bf01ef99a7aebb464f50568aec45c8364791805f77a7/cache-dependencies-0.7.7.41.tar.gz" } ], "0.7.7.42": [ { "comment_text": "", "digests": { "md5": "e5a353c0d51ecc4c3a6f379317fd04c9", "sha256": "bebfb5df11e94f61d746224594e41c7ab3ddc9bcbe4aa53d6b249d33276b4e99" }, "downloads": -1, "filename": "cache-dependencies-0.7.7.42.tar.gz", "has_sig": false, "md5_digest": "e5a353c0d51ecc4c3a6f379317fd04c9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 43014, "upload_time": "2016-12-13T02:47:23", "url": "https://files.pythonhosted.org/packages/7f/c6/8e0972cb1f15064c99fff3af3bcfd63018ad869da6b11a2e388a8fa3be62/cache-dependencies-0.7.7.42.tar.gz" } ], "0.7.7.43": [ { "comment_text": "", "digests": { "md5": "40800e3a3e1984dee33977db7f6c1c2d", "sha256": "f93cc8bb014458bfb9153dcbd43dfd0745d4399b4080acf2d66aca8837e31e13" }, "downloads": -1, "filename": "cache-dependencies-0.7.7.43.tar.gz", "has_sig": false, "md5_digest": "40800e3a3e1984dee33977db7f6c1c2d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 44018, "upload_time": "2016-12-18T02:16:06", "url": "https://files.pythonhosted.org/packages/fa/40/ce849522caad575d20287488bc807a4dc376f934c345dcc655cf52542b8b/cache-dependencies-0.7.7.43.tar.gz" } ], "0.7.7.44": [ { "comment_text": "", "digests": { "md5": "5479ae0bef5aa2b3cce5199cbdb3f8e3", "sha256": "818a64cf9dfcc8045f0cdebbc4ac46bbe1ef6fe8216ebc995d55ff94b6502712" }, "downloads": -1, "filename": "cache-dependencies-0.7.7.44.tar.gz", "has_sig": false, "md5_digest": "5479ae0bef5aa2b3cce5199cbdb3f8e3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 44335, "upload_time": "2017-07-04T01:19:41", "url": "https://files.pythonhosted.org/packages/37/a4/cf398f09c55428ebaf9386f5c8c2e527a4bf948a1f13627169ce4248fd3d/cache-dependencies-0.7.7.44.tar.gz" } ], "0.7.7.45": [ { "comment_text": "", "digests": { "md5": "0f9703c10de4087c53f8cd8166d22e8f", "sha256": "a396c0bc7e29d9406ff66b23acc64a943218a490d6b9fcaa30b44407bb24b8dc" }, "downloads": -1, "filename": "cache-dependencies-0.7.7.45.tar.gz", "has_sig": false, "md5_digest": "0f9703c10de4087c53f8cd8166d22e8f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 44327, "upload_time": "2017-07-28T03:45:35", "url": "https://files.pythonhosted.org/packages/41/57/c649a7abfb2c55e8796a25ee8c822622550affdf382981fa4915e91e7b9f/cache-dependencies-0.7.7.45.tar.gz" } ], "0.7.7.47": [ { "comment_text": "", "digests": { "md5": "ad79ff513b9e6df9e59bde0dfdd3a61e", "sha256": "9e5541244241a21547cbdbd03e7616e8a51eecd1105c04935f322539700ffd3e" }, "downloads": -1, "filename": "cache-dependencies-0.7.7.47.tar.gz", "has_sig": false, "md5_digest": "ad79ff513b9e6df9e59bde0dfdd3a61e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 44721, "upload_time": "2017-07-30T15:48:09", "url": "https://files.pythonhosted.org/packages/a5/c3/05eb2596abe6e20566f8f6aa58a2b20323c80bd602336bb863d942d54991/cache-dependencies-0.7.7.47.tar.gz" } ], "0.7.7.48": [ { "comment_text": "", "digests": { "md5": "90181b4266082d89168f672458dce65d", "sha256": "2407487fd6244ad91ceb90c570e353686fa1ee62fb6081d9d3255bc5fd1a3227" }, "downloads": -1, "filename": "cache-dependencies-0.7.7.48.tar.gz", "has_sig": false, "md5_digest": "90181b4266082d89168f672458dce65d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 44724, "upload_time": "2017-10-24T23:06:35", "url": "https://files.pythonhosted.org/packages/2d/80/378c2973c1d2bac60f8563de513f731a199350fc554210839ebcf377b0dc/cache-dependencies-0.7.7.48.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "90181b4266082d89168f672458dce65d", "sha256": "2407487fd6244ad91ceb90c570e353686fa1ee62fb6081d9d3255bc5fd1a3227" }, "downloads": -1, "filename": "cache-dependencies-0.7.7.48.tar.gz", "has_sig": false, "md5_digest": "90181b4266082d89168f672458dce65d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 44724, "upload_time": "2017-10-24T23:06:35", "url": "https://files.pythonhosted.org/packages/2d/80/378c2973c1d2bac60f8563de513f731a199350fc554210839ebcf377b0dc/cache-dependencies-0.7.7.48.tar.gz" } ] }