Package: django-ultracache
Notehttps://github.com/hedleyroos/django-ultracacheis the official home of the project. It has moved fromhttps://github.com/praekelt/django-ultracache.Django UltracacheCache views, template fragments and arbitrary Python code. Monitor Django object changes to perform automatic fine-grained cache invalidation from Django level, through proxies, to the browser.ContentsNoteDjango UltracacheOverviewInstallationFeaturesUsageThecached_getandultracacheview decoratorsTheultracachetemplate tagSpecifying a good cache keyDjango Rest Framework viewset cachingPurgersOther settingsHow does it work?TipsAuthorsChangelog2.22.1.12.1.02.0.01.11.121.11.111.11.101.11.91.11.81.11.71.11.61.11.51.11.41.11.31.11.21.11.11.11.01.10.21.10.11.9.11.9.00.3.80.3.70.3.60.3.50.3.40.3.30.3.20.3.10.30.20.1.60.1.50.1.40.1.30.1.20.1.10.1OverviewCache views, template fragments and arbitrary Python code. Once cached we
either avoid database queries and expensive computations, depending on the use
case. In all cases affected caches are automatically expired when objects “red”
or “blue” are modified, without us having to explicitly make the cache aware of
“red” or “blue”.View:from ultracache.decorators import ultracache

# The decorator with no parameters automatically caches on the request path
# and a minimal
# set of hidden parameters.
@ultracache(300)
class MyView(TemplateView):
    template_name = "my_view.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        # The URL that was called is eg. http://mysite.com/myview/blue.
        # This view remains cached until "blue" is modified by any other
        # code.
        context["color"] = Color.objects.get(slug=kwargs["color_slug"])

        # Retrieve "red". Even though we never use red further in this code
        # the cached view is still expired when red is modified by any
        # other code.
        red = Color.objects.get(slug="red")

        return contextTemplate:{# variable "color" is the object "blue" #}
{% load ultracache_tags %}
{% ultracache 300 "color-info" color.pk %}
    {# expensive properties follow #}
    {{ color.compute_valid_hex_codes }}
    {{ color.name_in_all_languages }}
{% endultracache %}Arbitrary Python:from ultracache.utils import Ultracache

...

color_slug = request.GET["color_slug"]
uc = Ultracache(300, "another-identifier", color_slug)
if uc:
    codes = uc.cached
else:
    color = Color.objects.get(slug=color_slug)
    codes = color.compute_valid_hex_codes()
    uc.cache(codes)
print(codes)View with more specific rules:from ultracache.decorators import ultracache

# Serve different cached versions for anonymous and authenticated users. "request"
# is always in scope in the decorator.
@ultracache(300, "request.user.is_authenticated")
class MyView(TemplateView):
    template_name = "my_view.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["show_private_messages"] = self.request.user.is_authenticated
        return contextInstallationInstall or adddjango-ultracacheto your Python path.Addultracacheto yourINSTALLED_APPSsetting.Addultracache.middleware.UltraCacheMiddlewareto yourMIDDLEWAREsetting. It is recommended to add it as one of the first entries.Ensuredjango.template.context_processors.requestis in the context processors setting.FeaturesCaches template fragments, views, Django Rest Framework viewsets.It takes the sites framework into consideration, allowing different caching per site.Crucially, it is aware of model objects that are subjected to its caching. When an object is modified
all affected cache key are automatically expired. This allows the user to set longer expiry times without having
to worry about stale content.The cache invalidation can be extended to issue purge commands to Varnish, Nginx or other reverse caching proxies.UsageThecached_getandultracacheview decoratorsdjango-ultracachealso provides decoratorscached_getandultracacheto cache your views. The parameters follow the same rules as theultracachetemplate tag except they must all resolve.request.get_full_path()is always implicitly added to the cache key. Theultracachedecorator is newer and cleaner, so use that where possible:from ultracache.decorators import cached_get, ultracache


class CachedView(TemplateView):
    template_name = "cached_view.html"

    @cached_get(300, "request.is_secure()", 456)
    def get(self, *args, **kwargs):
        return super(CachedView, self).get(*args, **kwargs)

@ultracache(300, "request.is_secure()", 456)
class AnotherCachedView(TemplateView):
    template_name = "cached_view.html"Thecached_getdecorator can be used in an URL pattern:from ultracache.decorators import cached_get

url(
    r"^cached-view/$",
    cached_get(3600)(TemplateView.as_view(
        template_name="myproduct/template.html"
    )),
    name="cached-view"
)Do not indiscriminately use the decorators. They only ever operate on GET
requests but cannot know if the code being wrapped retrieves data from eg. the
session. In such a case they will cache things they are not supposed to cache.If your view is used by more than one URL pattern then it is highly recommended
to apply thecached_getdecorator in the URL pattern. Applying it directly
to thegetmethod may lead to cache collisions, especially ifget_template_namesis overridden.Theultracachetemplate tagdjango-ultracacheprovides a template tag{% ultracache %}that
functions much like Django’s standard cache template tag; however, it takes the
sites framework into consideration, allowing different caching per site, and it
handles undefined variables.Simplest use case:{% load ultracache_tags %}
{% ultracache 3600 "my_identifier" object 123 undefined "string" %}
    {{ object.title }}
{% endultracache %}The tag can be nested.ultracacheis aware of all model objects that are subjected to its caching.
In this example cache keysouterandinner_oneare expired when object one is changed but
cache keyinner_tworemains unaffected:{% load ultracache_tags %}
{% ultracache 1200 "outer" %}
    {% ultracache 1200 "inner_one" %}
        title = {{ one.title }}
    {% endultracache %}
    {% ultracache 1200 "inner_two" %}
        title = {{ two.title }}
    {% endultracache %}
{% endultracache %}Specifying a good cache keyThe cache key decides whether a piece of code or template is going to be evaluated further. The
cache key must therefore accurately and minimally describe what is being subjected to caching.todoDjango Rest Framework viewset cachingCachelistandretrieveactions on viewsets:# Cache all viewsets
ULTRACACHE = {
    "drf": {"viewsets": {"*": {}}}

}

# Cache a specific viewset by name
ULTRACACHE = {
    "drf": {"viewsets": {"my.app.MyViewset": {}}}

}

# Cache a specific viewset by class
ULTRACACHE = {
    "drf": {"viewsets": {MyViewset: {}}}

}

# Timeouts default to 300 seconds
ULTRACACHE = {
    "drf": {"viewsets": {"*": {"timeout": 1200}}}

}

# Evaluate code to append to the cache key. This example caches differently
# depending on whether the user is logged in or not.
ULTRACACHE = {
    "drf": {"viewsets": {"*": {"evaluate": "request.user.is_anonymous"}}}

}

# Evaluate code to append to the cache key via a callable.
def mycallable(viewset, request):
    if viewset.__class__.__name__ == "foo":
        return request.user.id

ULTRACACHE = {
    "drf": {"viewsets": {"*": {"evaluate": mycallable}}}

}PurgersYou can create custom reverse caching proxy purgers. Seepurgers.pyfor examples:ULTRACACHE = {
    "purge": {"method": "myproduct.purgers.squid"}
}The most useful purger isbroadcast. As the name implies it broadcasts purge
instructions to a queue. Note that you need celery running and configured to
write to a RabbitMQ instance for this to work correctly.The purge instructions are consumed by thecache-purge-consumer.pyscript.
The script reads a purge instruction from the queue and then sends a purge
instruction to an associated reverse caching proxy. To run the script:virtualenv ve
./ve/bin/pip install -e .
./ve/bin/python bin/cache-purge-consumer.py -c config.yamlThe config file has these options:rabbit-urlSpecify RabbitMQ connection parameters in the AMQP URL formatamqp://username:password@host:port/<virtual_host>[?query-string].Optional. Defaults to amqp://guest:guest@127.0.0.1:5672/%2F.
Note the URL encoding for the path.hostA reverse caching proxy may be responsible for many domains (hosts), and
ultracache will keep track of the host that is involved in a purge request;
however, if you have a use case that does not supply a hostname, eg. doing a
PURGE request via curl, then forcing a hostname solves the use case.Optional.proxy-addressThe IP address or hostname of the reverse caching proxy.Optional. Defaults to 127.0.0.1.logfileSet to a file to log all purge instructions. Specifystdoutto log to
standard out.Optional.Other settingsAutomatic invalidation defaults to true. To disable automatic invalidation set:ULTRACACHE = {
    "invalidate": False
}django-ultracachemaintains a registry in Django’s caching backend (seeHow does it work). This registry can”t be allowed to grow unchecked, thus a
limit is imposed on the registry size. It would be inefficient to impose a size
limit on the entire registry so a maximum size is set per cached value. It
defaults to 1000000 bytes:ULTRACACHE = {
    "max-registry-value-size": 10000
}It is highly recommended to use a backend that supports compression because a
larger size improves cache coherency.If you make use of a reverse caching proxy then you need the original set of
request headers (or a relevant subset) to purge paths from the proxy correctly.
The problem with the modern web is the sheer amount of request headers present
on every request would lead to a large number of entries having to be stored bydjango-ultracachein Django’s caching backend. Your proxy probably has a
custom hash computation rule that considers only the request path (always
implied) and Django’s sessionid cookie, so define a setting to also consider only
the cookie on the Django side:ULTRACACHE = {
    "consider-headers": ["cookie"]
}If you only need to consider some cookies then set:ULTRACACHE = {
    "consider-cookies": ["sessionid", "some-other-cookie"]
}How does it work?django-ultracachemonkey patchesdjango.template.base.Variable._resolve_lookupanddjango.db.models.Model.__getattribute__to make a record of model objects
as they are resolved. Theultracachetemplate tag,ultracachedecorator
andultracachecontext manager inspect the list of objects contained
within them and keep a registry in Django’s caching backend. Apost_savesignal handler monitors objects for changes and expires the appropriate cache
keys.TipsIf you are running a cluster of Django nodes then ensure that they use a shared caching backend.AuthorsHedley RoosChangelog2.2Django 4.0 compatibility.2.1.1Ensure cache coherency should a purger fail.2.1.0Django 3 compatibility.Fix potential thread local residual data issue.2.0.0Remove dependency on the sites framework everywhere. The sites framework is still automatically
considered if an installed app.Do not store metadata in the request anymore but in a list on thread locals.Introduce class utils.Ultracache to subject arbitrary pieces of Python code to caching.Drop Django 1 support.1.11.12Simpler class based decorator.Add Django 2.1 and Python 3.6 tests.1.11.11Add a test for tasks.1.11.10Ensure a working error message if pika is not found.cached_getnow considers any object accessed in get_context_data and not just objects accessed in the view template.The original request headers are now sent to the purgers along with the path. This enables fine-grained proxy invalidation.Django 2.0 and Python 3 compatibility. Django 1.9 support has been dropped.1.11.9Simplify the DRF caching implementation. It also now considers objects touched by sub-serializers.1.11.8The DRF settings now accept dotted names.The DRF setting now accepts a callable whose result forms part of the cache key.1.11.7Use pickle to cache DRF data because DRF uses a Decimal type that isn’t recognized by Python’s json library.1.11.6Adjust the DRF decorator so it can be used in more places.1.11.5Django Rest Framework caching does not cache the entire response anymore, only the data and headers.1.11.4Move the twisted work todjango-ultracache-twisted.Clearly raise exception if libraries are not found.1.11.3Move the twisted directory one lower.1.11.2Package the product properly so all directories are included.1.11.1More defensive code to ensure we don’t interfere during migrations in a test run.1.11.0Introducerabbitmq-urlsetting for use bybroadcast_purgetask.Django 1.11 support.Deprecate Django 1.6 support.1.10.2Remove logic that depends on SITE_ID so site can also be inferred from the request.1.10.1Add caching for Django Rest Framework viewsets.Django 1.10 compatibility.1.9.1Add missing import only surfacing in certain code paths.Invalidatesetting was not being loaded properly. Fixed.Handle content types RuntimeError when content types have not been migrated yet.1.9.0Move to tox for tests.Django 1.9 compatibility.0.3.8Honor therawparameter send along by loaddata. It prevents redundant post_save handling.0.3.7Revert the adding of the template name. It introduces a performance penalty in a WSGI environment.Further reduce the number of writes to the cache.0.3.6Add template name (if possible) to the caching key.Reduce number of calls to set_many.0.3.5Keep the metadata cache size in check to prevent possibly infinite growth.0.3.4Prevent redundant sets.Work around an apparent Python bug related todi[k].append(v)vsdi[k] = di[k] + [v]. The latter is safe.0.3.3Handle case where one cached view renders another cached view inside it, thus potentially sharing the same cache key.0.3.2Theultracachetemplate tag now only caches HEAD and GET requests.0.3.1Trivial release to work around Pypi errors of the day.0.3Replacecache.getin for loop withcache.get_many.0.2Do not automatically addrequest.get_full_path()if any ofrequest.get_full_path(),request.pathorrequest.path_infois an argument forcached_get.0.1.6Also cache response headers.0.1.5Explicitly check for GET and HEAD request method and cache only those requests.0.1.4Rewrite decorator to be function based instead of class based so it is easier to use in urls.py.0.1.3cached_getdecorator now does not cache if request contains messages.0.1.2Fix HTTPResponse caching bug.0.1.1Handle case where a view returns an HTTPResponse object.0.1Initial release.