kopia lustrzana https://github.com/wagtail/wagtail
Allow specifying an alternative storage backend for image renditions
- add setting `WAGTAILIMAGES_RENDITION_STORAGE` - add AbstractRendition file storage to use new setting - resolves #3183pull/8166/head
rodzic
7d3ee400fe
commit
1c7c5cfc0b
|
@ -41,6 +41,7 @@ Changelog
|
|||
* Add documentation that describes how to use `ModelAdmin` to manage `Tag`s (Abdulmajeed Isa)
|
||||
* Rename the setting `BASE_URL` (undocumented) to `WAGTAILADMIN_BASE_URL` and add to documentation, `BASE_URL` will be removed in a future release (Sandil Ranasinghe)
|
||||
* Validate to and from email addresses within form builder pages when using `AbstractEmailForm` (Jake Howard)
|
||||
* Add `WAGTAILIMAGES_RENDITION_STORAGE` setting to allow an alternative image rendition storage (Heather White)
|
||||
* Fix: When using `simple_translations` ensure that the user is redirected to the page edit view when submitting for a single locale (Mitchel Cabuloy)
|
||||
* Fix: When previewing unsaved changes to `Form` pages, ensure that all added fields are correctly shown in the preview (Joshua Munn)
|
||||
* Fix: When Documents (e.g. PDFs) have been configured to be served inline via `WAGTAILDOCS_CONTENT_TYPES` & `WAGTAILDOCS_INLINE_CONTENT_TYPES` ensure that the filename is correctly set in the `Content-Disposition` header so that saving the files will use the correct filename (John-Scott Atlakson)
|
||||
|
|
|
@ -586,6 +586,7 @@ Contributors
|
|||
* Abdulmajeed Isa
|
||||
* Sandil Ranasinghe
|
||||
* Caio Jhonny
|
||||
* Heather White
|
||||
|
||||
Translators
|
||||
===========
|
||||
|
|
|
@ -335,6 +335,19 @@ Specifies the number of items per page shown when viewing an image's usage (see
|
|||
|
||||
Specifies the number of images shown per page in the image chooser modal.
|
||||
|
||||
.. _wagtailimages_rendition_storage:
|
||||
|
||||
``WAGTAILIMAGES_RENDITION_STORAGE``
|
||||
-----------------------------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
WAGTAILIMAGES_RENDITION_STORAGE = 'myapp.backends.MyCustomStorage'
|
||||
|
||||
This setting allows image renditions to be stored using an alternative storage backend. The default is ``None``, which will use Django's default `FileSystemStorage`.
|
||||
|
||||
Custom storage classes should subclass ``django.core.files.storage.Storage``. See the :doc:`Django file storage API <django:ref/files/storage>`.
|
||||
|
||||
Documents
|
||||
=========
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ class LandingPage(Page):
|
|||
* Add documentation that describes how to use `ModelAdmin` to manage `Tag`s (Abdulmajeed Isa)
|
||||
* Rename the setting `BASE_URL` (undocumented) to [`WAGTAILADMIN_BASE_URL`](wagtailadmin_base_url) and add to documentation, `BASE_URL` will be removed in a future release (Sandil Ranasinghe)
|
||||
* Validate to and from email addresses within form builder pages when using `AbstractEmailForm` (Jake Howard)
|
||||
* Add [`WAGTAILIMAGES_RENDITION_STORAGE`](wagtailimages_rendition_storage) setting to allow an alternative image rendition storage (Heather White)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
|
|
@ -10,10 +10,12 @@ 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.core.files.storage import default_storage
|
||||
from django.db import models
|
||||
from django.forms.utils import flatatt
|
||||
from django.urls import reverse
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.module_loading import import_string
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from taggit.managers import TaggableManager
|
||||
|
@ -70,6 +72,21 @@ def get_rendition_upload_to(instance, filename):
|
|||
return instance.get_upload_to(filename)
|
||||
|
||||
|
||||
def get_rendition_storage():
|
||||
"""
|
||||
Obtain the storage object for an image rendition file.
|
||||
Returns custom storage (if defined), or the default storage.
|
||||
|
||||
This needs to be a module-level function, because we do not yet
|
||||
have an instance when Django loads the models.
|
||||
"""
|
||||
storage = getattr(settings, "WAGTAILIMAGES_RENDITION_STORAGE", default_storage)
|
||||
if isinstance(storage, str):
|
||||
module = import_string(storage)
|
||||
storage = module()
|
||||
return storage
|
||||
|
||||
|
||||
class ImageFileMixin:
|
||||
def is_stored_locally(self):
|
||||
"""
|
||||
|
@ -597,7 +614,10 @@ class Filter:
|
|||
class AbstractRendition(ImageFileMixin, models.Model):
|
||||
filter_spec = models.CharField(max_length=255, db_index=True)
|
||||
file = models.ImageField(
|
||||
upload_to=get_rendition_upload_to, width_field="width", height_field="height"
|
||||
upload_to=get_rendition_upload_to,
|
||||
storage=get_rendition_storage,
|
||||
width_field="width",
|
||||
height_field="height",
|
||||
)
|
||||
width = models.IntegerField(editable=False)
|
||||
height = models.IntegerField(editable=False)
|
||||
|
|
|
@ -3,6 +3,7 @@ import unittest
|
|||
from django.contrib.auth.models import Group, Permission
|
||||
from django.core.cache import caches
|
||||
from django.core.files import File
|
||||
from django.core.files.storage import DefaultStorage, Storage
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.db.utils import IntegrityError
|
||||
from django.test import TestCase
|
||||
|
@ -10,7 +11,7 @@ from django.test.utils import override_settings
|
|||
from django.urls import reverse
|
||||
from willow.image import Image as WillowImage
|
||||
|
||||
from wagtail.images.models import Rendition, SourceImageIOError
|
||||
from wagtail.images.models import Rendition, SourceImageIOError, get_rendition_storage
|
||||
from wagtail.images.rect import Rect
|
||||
from wagtail.models import Collection, GroupCollectionPermission, Page
|
||||
from wagtail.test.testapp.models import (
|
||||
|
@ -23,6 +24,11 @@ from wagtail.test.utils import WagtailTestUtils
|
|||
from .utils import Image, get_test_image_file
|
||||
|
||||
|
||||
class CustomStorage(Storage):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
|
||||
class TestImage(TestCase):
|
||||
def setUp(self):
|
||||
# Create an image for running tests on
|
||||
|
@ -346,6 +352,40 @@ class TestRenditions(TestCase):
|
|||
rendition.background_position_style, "background-position: 50% 50%;"
|
||||
)
|
||||
|
||||
def test_custom_rendition_backend_setting(self):
|
||||
"""
|
||||
Test the usage of WAGTAILIMAGES_RENDITION_STORAGE setting.
|
||||
"""
|
||||
# when setting is not set, instance.get_storage() returns DefaultStorage
|
||||
from django.conf import settings
|
||||
|
||||
bkp = settings
|
||||
|
||||
self.assertFalse(hasattr(settings, "WAGTAILIMAGES_RENDITION_STORAGE"))
|
||||
rendition1 = self.image.get_rendition("min-120x120")
|
||||
self.assertIsInstance(rendition1.image.file.storage, DefaultStorage)
|
||||
|
||||
# when setting is set to a path
|
||||
setattr(
|
||||
settings,
|
||||
"WAGTAILIMAGES_RENDITION_STORAGE",
|
||||
"wagtail.images.tests.test_models.CustomStorage",
|
||||
)
|
||||
backend = get_rendition_storage()
|
||||
self.assertIsInstance(backend, CustomStorage)
|
||||
|
||||
# when setting is set directly, get_rendition_storage() returns the custom storage backend
|
||||
class CustomStorage2(Storage):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
setattr(settings, "WAGTAILIMAGES_RENDITION_STORAGE", CustomStorage2())
|
||||
backend = get_rendition_storage()
|
||||
self.assertIsInstance(backend, CustomStorage2)
|
||||
|
||||
# clean up
|
||||
settings = bkp
|
||||
|
||||
|
||||
class TestUsageCount(TestCase):
|
||||
fixtures = ["test.json"]
|
||||
|
|
Ładowanie…
Reference in New Issue