Cache image renditions (#4883)

pull/5941/head
Tom Dyson 2018-11-01 23:26:40 +00:00 zatwierdzone przez Matt Westcott
rodzic 23af29d35c
commit f37da8f7d8
5 zmienionych plików z 73 dodań i 1 usunięć

Wyświetl plik

@ -25,6 +25,7 @@ Changelog
* ListBlocks now call child block `bulk_to_python` if defined (Andy Chosak)
* Site settings are now identifiable/cachable by request as well as site (Andy Babic)
* Added `select_related` attribute to site settings to enable more efficient fetching of foreign key values (Andy Babic)
* Add caching of image renditions (Tom Dyson, Tim Kamanin)
* Fix: Added ARIA alert role to live search forms in the admin (Casper Timmers)
* Fix: Reorder login form elements to match expected tab order (Kjartan Sverrisson)
* Fix: Re-add 'Close Explorer' button on mobile viewports (Sævar Öfjörð Magnússon)

Wyświetl plik

@ -30,6 +30,28 @@ We recommend `Redis <https://redis.io/>`_ as a fast, persistent cache. Install R
}
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.
.. code-block:: python
CACHES = {
'default': {...},
'renditions': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
'TIMEOUT': 600,
'OPTIONS': {
'MAX_ENTRIES': 1000
}
}
}
Search
------

Wyświetl plik

@ -38,6 +38,7 @@ Other features
* ListBLocks now call child block ``bulk_to_python`` if defined (Andy Chosak)
* Site settings are now identifiable/cachable by request as well as site (Andy Babic)
* Added ``select_related`` attribute to site settings to enable more efficient fetching of foreign key values (Andy Babic)
* Add caching of image renditions (Tom Dyson, Tim Kamanin)
Bug fixes

Wyświetl plik

@ -6,6 +6,7 @@ from io import BytesIO
from django.conf import settings
from django.core import checks
from django.core.cache import InvalidCacheBackendError, caches
from django.core.files import File
from django.db import models
from django.forms.utils import flatatt
@ -277,6 +278,22 @@ class AbstractImage(CollectionMember, index.Indexed, models.Model):
filter = Filter(spec=filter)
cache_key = filter.get_cache_key(self)
try:
rendition_caching = True
cache = caches['renditions']
rendition_cache_key = "image-{}-{}-{}".format(
self.id,
cache_key,
filter.spec
)
cached_rendition = cache.get(rendition_cache_key)
if cached_rendition:
return cached_rendition
except InvalidCacheBackendError:
rendition_caching = False
Rendition = self.get_rendition_model()
try:
@ -314,6 +331,9 @@ class AbstractImage(CollectionMember, index.Indexed, models.Model):
defaults={'file': File(generated_image.f, name=output_filename)}
)
if rendition_caching:
cache.set(rendition_cache_key, rendition)
return rendition
def is_portrait(self):

Wyświetl plik

@ -2,6 +2,7 @@ import unittest
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group, Permission
from django.core.cache import caches
from django.core.files.uploadedfile import SimpleUploadedFile
from django.db.utils import IntegrityError
from django.test import TestCase
@ -14,7 +15,6 @@ from wagtail.images.models import Rendition, SourceImageIOError
from wagtail.images.rect import Rect
from wagtail.tests.testapp.models import EventPage, EventPageCarouselItem
from wagtail.tests.utils import WagtailTestUtils
from .utils import Image, get_test_image_file
@ -252,6 +252,32 @@ class TestRenditions(TestCase):
rendition = self.image.get_rendition('width-400')
self.assertEqual(rendition.alt, "Test image")
@override_settings(
CACHES={
'renditions': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
},
},
)
def test_renditions_cache_backend(self):
cache = caches['renditions']
rendition = self.image.get_rendition('width-500')
rendition_cache_key = "image-{}-{}-{}".format(
rendition.image.id,
rendition.focal_point_key,
rendition.filter_spec
)
# Check rendition is saved to cache
self.assertEqual(cache.get(rendition_cache_key), rendition)
# Mark a rendition to check it comes from cache
rendition._from_cache = True
cache.set(rendition_cache_key, rendition)
# Check if get_rendition returns the rendition from cache
self.assertEqual(self.image.get_rendition('width-500')._from_cache, True)
class TestUsageCount(TestCase):
fixtures = ['test.json']
@ -360,6 +386,7 @@ class TestIssue573(TestCase):
This tests for a bug which causes filename limit on Renditions to be reached
when the Image has a long original filename and a big focal point key
"""
def test_issue_573(self):
# Create an image with a big filename and focal point
image = Image.objects.create(
@ -500,6 +527,7 @@ class TestFilenameReduction(TestCase):
This tests for a bug which results in filenames without extensions
causing an infinite loop
"""
def test_filename_reduction_no_ext(self):
# Create an image with a big filename and no extension
image = Image.objects.create(