kopia lustrzana https://github.com/wagtail/wagtail
Cache image renditions (#4883)
rodzic
23af29d35c
commit
f37da8f7d8
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
------
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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(
|
||||
|
|
Ładowanie…
Reference in New Issue