{ "info": { "author": "Brian Jay Stanley", "author_email": "brian@brianjaystanley.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "``django-cachetree`` provides caching of configurable trees of related model\ninstances in Django. For example, with ``django-cachetree`` you could easily\ncache a user instance and the user's photos and comments on a photo-sharing\nsite as a single item in the cache. When a user is fetched from the database,\nits related objects are \"prefetched\" before the user object is set in the\ncache. This means that when you retrieve the user object from the cache, the\nrelated objects are there with it and you can access them without hitting the\ndatabase (or hitting the cache again)::\n\n user = User.objects.get_cached(pk=1) # user not yet in cache, hits the \n # database and prefetches related objects\n\n ....\n \n user = User.objects.get_cached(pk=1) # hits the cache\n photos = user.photo_set.all()\n print photos[0].title # doesn't hit database or cache\n comments = user.comment_set.all()\n print comments[0].date # doesn't hit database or cache\n\nYou can configure ``django-cachetree`` to cache related objects of related\nobjects of related objects, to any depth. For example, on a blog, you could\ncache author objects along with their set of blog entries, the set of comments\nfor each of those entries, and the commenter for each of those comments.\n\n``django-cachetree`` automatically invalidates cached objects when they or the\nrelated objects cached with them are changed, deleted, or created.\n\nRequirements \n============ \n``django-cachetree`` requires Django 1.3 and Python 2.5, 2.6, or 2.7.\n\nInstallation\n============\nYou can install ``django-cachetree`` with ::\n\n pip install django-cachetree\n\nor ::\n\n easy_install django-cachetree\n\nThis will add ``cachetree`` to your Python path. Add ``'cachetree'`` to your ``INSTALLED_APPS``, and add ``'cachetree.middleware.InstallCachetree'`` to your middleware classes. This will add a ``get_cached`` method to\nthe default manager for each of your cached models. (Note that because\n``get_cached`` is added to the manager class, it will be available on all\ninstances of that manager class. However, attempting to use it on a model not defined in your ``CACHETREE`` setting will raise a ``ValueError``.) If\ninvalidation is enabled, ``cachetree.install()`` also registers signal\nhandlers that are used for invalidation.\n\nInstalling ``cachetree`` via middleware will only work if there is a page request to trigger the middleware. To install and use ``cachetree`` outside of a request-response context (for example, in a test suite), run ::\n\n cachetree.install()\n \nin your testrunner or at the bottom of your models file. \n\n\nThe ``CACHETREE`` setting\n=================================\nTo use ``django-cachetree``, add a ``CACHETREE`` setting to ``settings.py``.\nThe ``CACHETREE`` setting consists of nested dictionaries that tell\n``django-cachetree`` what to cache. The keys in the topmost dictionary should\ncontain the ``app_label`` for each app that has models you wish to cache. Each\n``app_label``'s dictionary should contain a key with the class name (as a\nstring) for each cached model in the app. These are the models whose managers\nwill provide a ``get_cached`` method, and are known as \"root models\" in\n``django-cachetree``'s terminology. For example, to cache ``Author`` and\n``Entry`` models but none of their related objects in an app called ``myapp``,\nyou would write::\n\n CACHETREE = {\n \"myapp\": {\n \"Author\": {},\n \"Entry\": {},\n }\n }\n\nThe dictionary for each root model can contain three optional keys,\n``\"timeout\"``, ``\"lookups\"``, and ``\"prefetch\"``.\n\n``timeout`` \n The timeout, in seconds, to use when caching instances of this model.\n Overrides your global timeout setting in ``CACHES``.\n \n``lookups``\n A tuple containing the field names that can be used as kwargs when calling\n ``get_cached`` for this model. By default, lookups are allowed by primary\n key. If your model's primary key field is ``id``, the default setting\n would be ``(\"pk\", \"id\")``.\n \n To lookup by a combination of fields, include the field names as a tuple\n within your ``lookups`` tuple. For example, to look up ``User`` instances\n by ``id`` or by ``first_name`` and ``last_name``::\n\n CACHETREE = {\n \"auth\": {\n \"User\": {\n \"lookups\": (\n \"id\",\n (\"first_name\", \"last_name\"),\n )\n }\n }\n }\n \n If invalidation is enabled, lookups are restricted to fields defined on\n the model, including ``ForeignKey`` fields and ``OneToOneField``\\s but\n excluding ``ManyToManyField``\\s. Specifying ``ManyToManyField``\\s or\n reverse ``ForeignKey`` or ``OneToOneField``\\s will raise\n ``cachetree.ImproperlyConfigured``. Lookup separators (for example,\n ``username__contains``) are also not allowed and will raise\n ``ImproperlyConfigured``. To know what keys to invalidate,\n ``django-cachetree`` requires exact lookups (which is the default when no\n lookup separator is used).\n \n``prefetch``\n A dictionary specifying the tree of related objects to prefetch and cache\n with the root model instance. Each key should be the attribute name (as a\n string) of the related instance(s) to be prefetched. Each key's value\n should be a dictionary of attribute names to prefetch on the related\n instance(s), or an empty dictionary (or ``None``) if no further\n relationships should be prefetched. Any relationship can be prefetched:\n ``OneToOneField``, ``ForeignKey``, and ``ManyToManyField``, forward or\n reverse. For example, to cache author objects, their set of entries, those\n entries' comments, and each comment's commenter, you might write::\n\n CACHETREE = {\n \"myapp\": {\n \"Author\": {\n \"lookups\": (\n \"pk\",\n \"id\",\n (\"first_name\", \"last_name\"),\n ),\n \"prefetch\": {\n \"entry_set\": {\n \"comment_set\": {\n \"commenter\": {},\n },\n },\n },\n },\n },\n }\n \n The above example assumes that each ``Author`` object is related to its\n entries by an ``entry_set`` attribute, each entry object is related to its\n comments by a ``comment_set`` attribute, and each comment object relates\n to its commenter by a ``commenter`` field. \n \n If invalidation is enabled, there is one restriction on prefetching. If\n you prefetch a ``ManyToManyField`` (forward or reverse) that defines a\n custom intermediary model (as specified with the ``through`` argument on\n the model field definition), you must also prefetch the attribute that\n points to the intermediary instances. For example, if you have an\n ``Entry`` model related to a ``Category`` model through a custom\n intermediary model called ``EntryCategory``, and you prefetch\n ``Entry.categories`` (a ``ManyToManyField``), you must also prefetch the\n ``Entry.entrycategory_set`` attribute that Django adds to your ``Entry``\n model, or ``ImproperlyConfigured`` will be raised.\n \nYou can find example ``CACHETREE`` settings in ``django-cachetree``'s test\nmodule, which defines models and settings covering all possible relationships.\n\nPrefetching ``ManyToManyField``\\s and Reverse ``ForeignKey``\\s\n==============================================================\nWhen you configure ``django-cachetree`` to cache a ``ManyToManyField`` or\nreverse ``ForeignKey``, such as ``user.photo_set`` (where ``Photo`` has a\nforeign key to ``User``), ``django-cachetree`` calls ``user.photo_set.all()``,\nevaluates the queryset, and caches the results on the ``user`` when\nprefetching. Subsequent calls to ``user.photo_set.all()`` will return the\ncached results, rather than returning a new queryset (which would require\nhitting the database again to evaluate). ``django-cachetree`` patches the manager on\n``ManyToManyField`` and ``ForeignKey`` descriptors to make this behavior\npossible. However, only the ``all()`` method is patched. If you call\n``user.photo_set.count()`` or ``user.photo_set.filter()`` or any other method\nbesides ``all()``, you will bypass the cached results and hit the database.\nAssuming your object set is not huge, you can avoid hitting the database by\ncalling ``all()`` and counting or filtering the results within your code.\n\nHow Invalidation Works\n======================\nWhen you call ``cachetree.install()``, ``django-cachetree`` analyzes your\n``CACHETREE`` setting and determines which relationships must be followed in\norder to traverse the tree backwards from prefetched related instances to\ntheir root model instances. Using this information, whenever a model defined\nin your ``CACHETREE`` setting (either as a root model or as a prefetched\nrelationship) is created, saved, or deleted (and in the case of\n``ManyToManyField``\\s and reverse ``ForeignKey``\\s, added, removed, or cleared\nusing the field manager's ``add()``, ``remove()``, or ``clear()`` methods),\n``django-cachetree`` traverses its relationships back to the root model\ninstance(s) that need to be invalidated. ``django-cachetree`` uses a\n``post_init`` signal handler to keep track of each instance's initial state,\nand when the instance changes and is saved, ``django-cachetree`` follows both\nthe instance's new and initial values to find the root model instances that\nneed to be invalidated. For example, if you cache ``Author`` objects along\nwith their ``entry_set``, and you change an ``Entry`` object's author,\n``django-cachetree`` will invalidate both the new and the initial ``Author``\nobjects for that entry.\n\n**Important Caveat**: ``django-cachetree`` does not perform invalidation when\nyou run an ``UPDATE`` query using a manager's ``update()`` method. You will\neither need to invalidate the affected instances yourself by calling\n``invalidate()`` (described below), rely on the cached objects to expire naturally,\nor avoid using ``update()``.\n \nCachetree Authentication Backend\n================================\nIf ``django.contrib.auth`` is installed in your project, you can use\n``django-cachetree``'s authentication backend::\n\n AUTHENTICATION_BACKENDS = (\n \"cachetree.auth.CachedModelBackend\",\n )\n\nThis will look in the cache before hitting the database when authenticating\nusers. Adding the ``auth.User`` model to your ``CACHETREE`` setting is\noptional. Not adding it implies the following settings::\n \n CACHETREE = {\n\n ...\n \n \"auth\": {\n \"User\": {\n \"lookups\":(\n \"pk\",\n \"username\",\n ),\n },\n },\n }\n\nIf you wish to allow additional lookups on ``User`` or to prefetch related\ninstances, explicitly define ``User`` in your ``CACHETREE`` setting.\n\nUtils\n=====\nThe following functions can be imported from ``cachetree``:\n\n``get_cached_object_or_404``\n Works like ``get_object_or_404``, but uses ``get_cached`` instead of ``get``. \n \n``invalidate(*instances)``\n Traverses relationships on each of the ``instances`` to find and invalidate\n its root model instance(s).\n\n``no_invalidation``\n Decorator that disables invalidation for the duration of the function it decorates.\n\nAdditional Settings\n===================\n``CACHETREE_DISABLE``\n Set to ``True`` to disable ``django-cachetree``. Calls to ``get_cached()``\n or ``get_cached_object_or_404()`` will use ``get()``. Calls to\n ``invalidate()`` and uses of the ``no_invalidation`` decorator will have\n no effect. This allows you to temporarily disable ``django-cachetree``\n without modifying any code. Default: ``False``.\n\n``CACHETREE_INVALIDATE``\n Set to ``False`` to disable invalidation. ``django-cachetree`` will\n continue to cache model objects but will not invalidate them when they\n change. Calls to ``invalidate()`` and uses of the ``no_invalidation``\n decorator will have no effect. Default: ``True``.\n\n``CACHETREE_MANY_RELATED_PREFIX``\n Controls the prefix ``django-cachetree`` uses when it prefetches a set of\n related objects and caches it on a model instance. In the example of\n ``author.entry_set.all()``, ``django-cachetree`` caches the author's set\n of entries as ``author._cached_entry_set``, and subsequent calls to\n ``author.entry_set.all()`` return this attribute. Normally you will not\n need to access this attribute directly, but this setting allows you to\n change the prefix in case of name conflicts. Default: ``_cached_``.", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/brianjaystanley/django-cachetree", "keywords": "django cache", "license": "MIT", "maintainer": null, "maintainer_email": null, "name": "django-cachetree", "package_url": "https://pypi.org/project/django-cachetree/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/django-cachetree/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/brianjaystanley/django-cachetree" }, "release_url": "https://pypi.org/project/django-cachetree/0.1.3/", "requires_dist": null, "requires_python": null, "summary": "cache configurable trees of related model instances in Django", "version": "0.1.3" }, "last_serial": 1532909, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "7cb15bb1229f93bdf8799e3df1628a52", "sha256": "48eb9a97141fecc37b0aa44b9c74955ddd2cf026979367db6e17cf4c80a584aa" }, "downloads": -1, "filename": "django-cachetree-0.1.0.zip", "has_sig": false, "md5_digest": "7cb15bb1229f93bdf8799e3df1628a52", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 37234, "upload_time": "2011-08-25T16:37:34", "url": "https://files.pythonhosted.org/packages/07/ab/2feff628221a2b68a6371e5418fbcdb5ba19186dd9bb91005e83280ec228/django-cachetree-0.1.0.zip" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "032f1b883d540f907a08517d7d943e5b", "sha256": "0f4e69bc9b8066c79a249377d6f5e82a17ca013b78706957f56966d5b1af4c6b" }, "downloads": -1, "filename": "django-cachetree-0.1.1.zip", "has_sig": false, "md5_digest": "032f1b883d540f907a08517d7d943e5b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 37361, "upload_time": "2011-08-30T17:49:33", "url": "https://files.pythonhosted.org/packages/86/b2/5822d9f63f77bd51db3c6d59afdf39e468129dde21b894d3a0fbc0f75c72/django-cachetree-0.1.1.zip" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "dca070ce73fea27ea5ce7f09eb561561", "sha256": "e57a60375fdba0c94b5d79f1770eea34746947c703f9fbe4964e2c1a1fcac71d" }, "downloads": -1, "filename": "django-cachetree-0.1.2.zip", "has_sig": false, "md5_digest": "dca070ce73fea27ea5ce7f09eb561561", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 37439, "upload_time": "2011-09-20T15:33:08", "url": "https://files.pythonhosted.org/packages/ab/be/0001f22b386bfb530edebb6ab7613dd1d80e6ea752937901b8f5c1623325/django-cachetree-0.1.2.zip" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "6272d8c742ddebe28fc6c387b7df2fe9", "sha256": "9ac48a2fa23c492106510a19e80408b73adec7eac01257829ec3c79777165dca" }, "downloads": -1, "filename": "django-cachetree-0.1.3.zip", "has_sig": false, "md5_digest": "6272d8c742ddebe28fc6c387b7df2fe9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 38447, "upload_time": "2015-05-04T19:01:19", "url": "https://files.pythonhosted.org/packages/86/4b/3ebb6884437fabc8291ec9e6e592964a0183d610e8a75dfc74d97cb85632/django-cachetree-0.1.3.zip" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "6272d8c742ddebe28fc6c387b7df2fe9", "sha256": "9ac48a2fa23c492106510a19e80408b73adec7eac01257829ec3c79777165dca" }, "downloads": -1, "filename": "django-cachetree-0.1.3.zip", "has_sig": false, "md5_digest": "6272d8c742ddebe28fc6c387b7df2fe9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 38447, "upload_time": "2015-05-04T19:01:19", "url": "https://files.pythonhosted.org/packages/86/4b/3ebb6884437fabc8291ec9e6e592964a0183d610e8a75dfc74d97cb85632/django-cachetree-0.1.3.zip" } ] }