Django Caching
Caching in Django kann auf verschiedenen Ebenen (oder Teilen der Site) implementiert werden. Sie können die gesamte Site oder bestimmte Teile mit verschiedenen Granularitätsstufen zwischenspeichern (in absteigender Reihenfolge der Granularität aufgeführt):
Caching Levels
ganze Webseite cachen
https://docs.djangoproject.com/en/stable/topics/cache/#the-per-site-cache
Views cachen
https://docs.djangoproject.com/en/stable/topics/cache/#the-per-view-cache
Teile von Templates cachen
https://docs.djangoproject.com/en/stable/topics/cache/#template-fragment-caching
Low Level Cache Api
https://docs.djangoproject.com/en/stable/topics/cache/#the-low-level-cache-api
Caching Backends
Django unterstützt verschiedene Caching-Backends.
MemCached: https://docs.djangoproject.com/en/stable/topics/cache/#memcached
Datenban: https://docs.djangoproject.com/en/stable/topics/cache/#database-caching
Dateisystem: https://docs.djangoproject.com/en/stable/topics/cache/#filesystem-caching
Local Memory: https://docs.djangoproject.com/en/stable/topics/cache/#local-memory-caching
Dummy Cache: https://docs.djangoproject.com/en/stable/topics/cache/#dummy-caching-for-development
Redis (ab Django 4.x): https://docs.djangoproject.com/en/ref/topics/cache/#redis
Für den Produtivbetrieb mit hohem Useraufkommen sollte Redis oder Memcached genutzt werden, da beide auf viele Server skaliert werden können (Redis Cluster).
Caching konfigurieren
in den settings.py
kann der Cache mit diversen Werten konfiguriert werden.
Hier konfigurieren wir einen Local-Memory-Cache für den Entwicklungsserver:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake',
}
}
views cachen
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def my_view(request):
...
oder in den URls
from django.views.decorators.cache import cache_page
urlpatterns = [
path('foo/<int:code>/', cache_page(60 * 15)(my_view)),
]
oder als Mixin
class CacheMixin:
cache_timeout = 60
def get_cache_timeout(self):
return self.cache_timeout
def dispatch(self, *a, **k):
return cache_page(self.get_cache_timeout())(super().dispatch)(*a, **k)
welches dann später in einer klassenbasierten View genutzt werden kann
class EventListView(CacheMixin, ListView):
...
Template Caching
Auch Teile des Templates können gecached werden:
{% load cache %}
{% cache 500 sidebar %}
.. sidebar ..
{% endcache %}
Hier im Beispiel cachen wir die Sidebar 500 Sekunden, erst danach wird der Block wieder gerendert.
auch in Abhängigkeit von Daten, zum Beispiel in Abhängigeit des Users:
{% load cache %}
{% cache 500 sidebar request.user.username %}
.. sidebar for logged in user ..
{% endcache %}
Low Level Api
Nicht immer wollen wir Templates, Views oder Querysets cachen. Oftmals kommt es vor, dass wir eigene Daten, zum Beispiel aus kostenintensiven Berechungen, für eine Zeitlang aus dem Cache servieren wollen. Dazu bietet Django eine Low Level Api an:
>> from django.core.cache import cache
>>> cache.set('my_key', 'hello, world!', 30)
>>> cache.get('my_key')
>> # Wait 30 seconds for 'my_key' to expire...
>>> cache.get('my_key')
None
>>> # wie gewöhnlich kann man bei Dicts auch mit Default-Werten arbeiten,
>>> # falls der Key nicht vorhanden ist.
>>> cache.get('my_key', 'defaultWert')
Manchmal kann es Sinn machen, mit Sentinel-Objekten zur arbeiten.
>>> sentinel = object()
>>> cache.get('my_key', sentinel) is sentinel
False
>>> # Wait 30 seconds for 'my_key' to expire...
>>> cache.get('my_key', sentinel) is sentinel
True
Zum Beispiel soll der Key Bank auf None gesetzt werden und 10 Sekunden im Cache bleiben. Würden wir einfach mit get(„bank“) arbeiten, wüssten wir nicht, ob der Value None ist oder der Key gar nicht im Cache vorhanden.
>>> # Cache setzen
>>> cache.set("bank", None, 10)
>>> # es wird None zurückgegeben (weil das der Value ist)
>>> cache.get("bank", sentinel) is sentinel
False
>>> is sentinel, es wird immer noch None
>>> cache.get("bank", sentinel)
False
>>> # get liefert jetzt als default das sentinel Objekt
>>> # und ist daher nicht mehr im Cache gespeichert
>>> cache.get("bank", sentinel) is sentinel
True