Browse Source

Always cache renditions

This should provide a big performance boost to those who don't set the cache, with minimal extra overhead.
Jake Howard 1 year ago
parent
commit
27a203f697

+ 8 - 0
docs/advanced_topics/images/renditions.md

@@ -54,6 +54,14 @@ The return value is a dictionary of renditions keyed by the specification string
 }
 }
 ```
 ```
 
 
+(caching_image_renditions)=
+
+## Caching image renditions
+
+Wagtail will cache image rendition lookups, which can improve the performance of pages which include many images.
+
+By default, Wagtail will try to use the cache called "renditions". If no such cache exists, it will fall back to using the default cache.
+
 (prefetching_image_renditions)=
 (prefetching_image_renditions)=
 
 
 ## Prefetching image renditions
 ## Prefetching image renditions

+ 1 - 5
docs/advanced_topics/performance.md

@@ -24,11 +24,7 @@ CACHES = {
 }
 }
 ```
 ```
 
 
-### Caching image renditions
-
-If you define a cache named 'renditions' (typically alongside your 'default' cache),
-Wagtail will cache image rendition lookups, which may improve the performance of pages
-which include many images.
+To use a different cache backend for [caching image renditions](caching_image_renditions), configure the "renditions" backend:
 
 
 ```python
 ```python
 CACHES = {
 CACHES = {

+ 27 - 32
wagtail/images/models.py

@@ -7,13 +7,13 @@ from concurrent.futures import ThreadPoolExecutor
 from contextlib import contextmanager
 from contextlib import contextmanager
 from io import BytesIO
 from io import BytesIO
 from tempfile import SpooledTemporaryFile
 from tempfile import SpooledTemporaryFile
-from typing import Dict, Iterable, List, Optional, Union
+from typing import Dict, Iterable, List, Union
 
 
 import willow
 import willow
 from django.apps import apps
 from django.apps import apps
 from django.conf import settings
 from django.conf import settings
 from django.core import checks
 from django.core import checks
-from django.core.cache import InvalidCacheBackendError, caches
+from django.core.cache import DEFAULT_CACHE_ALIAS, InvalidCacheBackendError, caches
 from django.core.cache.backends.base import BaseCache
 from django.core.cache.backends.base import BaseCache
 from django.core.files import File
 from django.core.files import File
 from django.core.files.base import ContentFile
 from django.core.files.base import ContentFile
@@ -428,11 +428,11 @@ class AbstractImage(ImageFileMixin, CollectionMember, index.Indexed, models.Mode
             pass
             pass
 
 
     @property
     @property
-    def renditions_cache(self) -> Optional[BaseCache]:
+    def renditions_cache(self) -> BaseCache:
         try:
         try:
             return caches["renditions"]
             return caches["renditions"]
         except InvalidCacheBackendError:
         except InvalidCacheBackendError:
-            return None
+            return caches[DEFAULT_CACHE_ALIAS]
 
 
     def get_rendition(self, filter: Union["Filter", str]) -> "AbstractRendition":
     def get_rendition(self, filter: Union["Filter", str]) -> "AbstractRendition":
         """
         """
@@ -455,11 +455,10 @@ class AbstractImage(ImageFileMixin, CollectionMember, index.Indexed, models.Mode
             # Reuse this rendition if requested again from this object
             # Reuse this rendition if requested again from this object
             self._add_to_prefetched_renditions(rendition)
             self._add_to_prefetched_renditions(rendition)
 
 
-        if self.renditions_cache:
-            cache_key = Rendition.construct_cache_key(
-                self.id, filter.get_cache_key(self), filter.spec
-            )
-            self.renditions_cache.set(cache_key, rendition)
+        cache_key = Rendition.construct_cache_key(
+            self.id, filter.get_cache_key(self), filter.spec
+        )
+        self.renditions_cache.set(cache_key, rendition)
 
 
         return rendition
         return rendition
 
 
@@ -523,18 +522,17 @@ class AbstractImage(ImageFileMixin, CollectionMember, index.Indexed, models.Mode
             self._add_to_prefetched_renditions(rendition)
             self._add_to_prefetched_renditions(rendition)
             renditions[filter] = rendition
             renditions[filter] = rendition
 
 
-        # If rendition caching is enabled, update the cache
-        if self.renditions_cache:
-            cache_additions = {
-                Rendition.construct_cache_key(
-                    self.id, filter.get_cache_key(self), filter.spec
-                ): rendition
-                for filter, rendition in renditions.items()
-                # prevent writing of cached data back to the cache
-                if not getattr(rendition, "_from_cache", False)
-            }
-            if cache_additions:
-                self.renditions_cache.set_many(cache_additions)
+        # Update the cache
+        cache_additions = {
+            Rendition.construct_cache_key(
+                self.id, filter.get_cache_key(self), filter.spec
+            ): rendition
+            for filter, rendition in renditions.items()
+            # prevent writing of cached data back to the cache
+            if not getattr(rendition, "_from_cache", False)
+        }
+        if cache_additions:
+            self.renditions_cache.set_many(cache_additions)
 
 
         # Return a dict in the expected format
         # Return a dict in the expected format
         return {filter.spec: rendition for filter, rendition in renditions.items()}
         return {filter.spec: rendition for filter, rendition in renditions.items()}
@@ -588,17 +586,14 @@ class AbstractImage(ImageFileMixin, CollectionMember, index.Indexed, models.Mode
             # Renditions are not prefetched, so attempt to find suitable
             # Renditions are not prefetched, so attempt to find suitable
             # items in the cache or database
             # items in the cache or database
 
 
-            # Query the cache first (if enabled)
-            if self.renditions_cache is not None:
-                cache_keys = [
-                    Rendition.construct_cache_key(
-                        self.id, filter.get_cache_key(self), spec
-                    )
-                    for spec, filter in filters_by_spec.items()
-                ]
-                for rendition in self.renditions_cache.get_many(cache_keys).values():
-                    filter = filters_by_spec[rendition.filter_spec]
-                    found[filter] = rendition
+            # Query the cache first
+            cache_keys = [
+                Rendition.construct_cache_key(self.id, filter.get_cache_key(self), spec)
+                for spec, filter in filters_by_spec.items()
+            ]
+            for rendition in self.renditions_cache.get_many(cache_keys).values():
+                filter = filters_by_spec[rendition.filter_spec]
+                found[filter] = rendition
 
 
             # For items not found in the cache, look in the database
             # For items not found in the cache, look in the database
             not_found = [f for f in filters if f not in found]
             not_found = [f for f in filters if f not in found]