I read that with the help of caching, you can achieve a significant acceleration of page generation, while saving server resources. win-win, how not to turn. Is it enough to hang on the view desired decorator , described in the documentation, so that everything is cool?

  • Good article, well done - kitscribe

1 answer 1

Enough for fully static pages. Not enough and harmful (leads to errors, not always obvious) for the pages of dynamic.


Suppose that we have a certain page that requires caching. It is not static, there are elements, the presence and appearance of which depends on the specific user and his rights. The simplest example is the header of the site where Привет, {{ username }} is written Привет, {{ username }} . There are also elements common to all users. The template itself looks something like this:

 {% include header.html %} {% for elem in elements %} <p>{{ elem.text }}</p> {% endfor %} {% if user.has_rights %} <button>Add new!</button> {% endfor %} 

where elements = Elements.objects.filter(display=True).all() , that is, the list of elements is common, but the button is for administrators only.

Another example is a store where the list of products is common, and the basket is different for everyone.

Django out of the box provides several ways to cache data:

  • Global for all requests : you need to enable UpdateCacheMiddleware and FetchFromCacheMiddleware :

     MIDDLEWARE_CLASSES = ( 'django.middleware.cache.UpdateCacheMiddleware', # ... Другие слои ... 'django.middleware.cache.FetchFromCacheMiddleware' ) 

    Globally - means the user Vasya having logged in will cache the data specific to his user (for example, the greeting "Привет, Вася!" ) And all users who came after Vasya will receive his greeting instead of theirs. And all the minutes or hours before fading they will see themselves as Vasya, and they will have no opportunity to cancel or avoid such behavior. This will be a sad behavior that confuses users. It is suitable if we have a couple of static pages and neither users nor dynamic content. But then why Django?

  • Individually for each view : @cache_page(<время в секундах>) Suffers from the same problems, but at least you can set the update period individually. TTL (Time to Live) will not make this tool magical, but it is suitable for some rare pages without a header with a greeting.
  • Cache something in the template using {% cache %} directive. Already much better - you can separately cache the header with a greeting for each user separately, and for anonymous users separately + general data separately. However, in this case the page generation speed suffers, because the template loading and rendering process is extremely slow and the speed benefits are not as high as might be expected. It is also not a fact that other template engines support this functionality. Also, the fact that we cashed the final result (HTML markup) does not eliminate the need to refer to the database in the view and we will then be completely in vain, because the results will not be used. However, such a solution also has the right to exist - HTML generation based on templates is not the fastest operation, but in a compressed form it takes a few megabytes per thousand pages. If we move away from performance, then from the point of view of architecture, the cache inside the templates is also not smooth. It is necessary, for example, to carefully remember all the display conditions, all the conditions in the view and in the template, which in the long run with several developers and a bunch of abstractions over the years can make development difficult and worse - fraught with subtle errors associated with caching specific parts for any one user group. For example, we do not take into account the status of superpolzovatel. Vasya-admin requested the page first after the moment of its swelling - and now in the cache there is a page with admin buttons. Or more often the opposite - admin Vasya will lose all his buttons, because the page for anonymous is in the cache.
  • Model-level caching provided by several third-party applications. It seems that this is a silver bullet, but in reality this approach has many restrictions and the most important restriction - all mechanisms are hidden from the programmer and if you connect this piece to an existing project, it will be difficult to answer whether something will break or not. With such fears, it will be impossible to use the main feature of this approach (caching without a TTL with updates on CRUD events). If the caching library provided guarantees that they would not get bogged down, the data in the cache would never go bad - this would be the best solution. The only solution that explicitly writes about guarantees (and supports the old 1.6+ genre) and inspires with this confidence is django-cachalot , however, I don’t know if this guarantees are fulfilled in practice in the short and long term. Even if so, other limitations come up - for example, the need to synchronize the clocks of multiple servers or replications.
  • Forget about all this, relying on internally caching Django inside the QuerySet . It could also be some kind of temporary solution, however, in this case, you won’t get enough memory for it.