kopia lustrzana https://github.com/wagtail/wagtail
catch errors on non existing images
rodzic
ab45915a90
commit
2dd3f42e25
|
@ -38,6 +38,7 @@ Changelog
|
|||
* Fix: `MenuItem` `url` parameter can now take a lazy URL (Adon Metcalfe, rayrayndwiga)
|
||||
* Fix: Added missing translation tag to InlinePanel 'Add' button (jnns)
|
||||
* Fix: Restored correct highlighting behaviour of rich text toolbar buttons
|
||||
* Fix: Rendering a missing image through ImageChooserBlock no longer breaks the whole page (Christian Peters)
|
||||
|
||||
1.2 (12.11.2015)
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -88,6 +88,7 @@ Bug fixes
|
|||
* ``MenuItem`` ``url`` parameter can now take a lazy URL (Adon Metcalfe, rayrayndwiga)
|
||||
* Added missing translation tag to InlinePanel 'Add' button (jnns)
|
||||
* Restored correct highlighting behaviour of rich text toolbar buttons
|
||||
* Rendering a missing image through ImageChooserBlock no longer breaks the whole page (Christian Peters)
|
||||
|
||||
|
||||
Upgrade considerations
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.utils.functional import cached_property
|
||||
|
||||
from wagtail.wagtailcore.blocks import ChooserBlock
|
||||
from .shortcuts import get_rendition_or_not_found
|
||||
|
||||
|
||||
class ImageChooserBlock(ChooserBlock):
|
||||
|
@ -16,6 +17,6 @@ class ImageChooserBlock(ChooserBlock):
|
|||
|
||||
def render_basic(self, value):
|
||||
if value:
|
||||
return value.get_rendition('original').img_tag()
|
||||
return get_rendition_or_not_found(value, 'original').img_tag()
|
||||
else:
|
||||
return ''
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.utils.html import escape
|
||||
|
||||
from wagtail.utils.apps import get_app_submodules
|
||||
from wagtail.wagtailimages.models import SourceImageIOError
|
||||
from .shortcuts import get_rendition_or_not_found
|
||||
|
||||
|
||||
class Format(object):
|
||||
|
@ -26,15 +26,7 @@ class Format(object):
|
|||
)
|
||||
|
||||
def image_to_html(self, image, alt_text, extra_attributes=''):
|
||||
try:
|
||||
rendition = image.get_rendition(self.filter_spec)
|
||||
except SourceImageIOError:
|
||||
# Image file is (probably) missing from /media/original_images - generate a dummy
|
||||
# rendition so that we just output a broken image, rather than crashing out completely
|
||||
# during rendering
|
||||
Rendition = image.renditions.model # pick up any custom Image / Rendition classes that may be in use
|
||||
rendition = Rendition(image=image, width=0, height=0)
|
||||
rendition.file.name = 'not-found'
|
||||
rendition = get_rendition_or_not_found(image, self.filter_spec)
|
||||
|
||||
if self.classnames:
|
||||
class_attr = 'class="%s" ' % escape(self.classnames)
|
||||
|
|
|
@ -2,25 +2,14 @@ from __future__ import absolute_import
|
|||
|
||||
from jinja2.ext import Extension
|
||||
|
||||
from wagtail.wagtailimages.models import SourceImageIOError
|
||||
from .shortcuts import get_rendition_or_not_found
|
||||
|
||||
|
||||
def image(image, filterspec, **attrs):
|
||||
if not image:
|
||||
return ''
|
||||
|
||||
try:
|
||||
rendition = image.get_rendition(filterspec)
|
||||
except SourceImageIOError:
|
||||
# It's fairly routine for people to pull down remote databases to their
|
||||
# local dev versions without retrieving the corresponding image files.
|
||||
# In such a case, we would get a SourceImageIOError at the point where we try to
|
||||
# create the resized version of a non-existent image. Since this is a
|
||||
# bit catastrophic for a missing image, we'll substitute a dummy
|
||||
# Rendition object so that we just output a broken link instead.
|
||||
Rendition = image.renditions.model # pick up any custom Image / Rendition classes that may be in use
|
||||
rendition = Rendition(image=image, width=0, height=0)
|
||||
rendition.file.name = 'not-found'
|
||||
rendition = get_rendition_or_not_found(image, filterspec)
|
||||
|
||||
if attrs:
|
||||
return rendition.img_tag(attrs)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# coding=utf-8
|
||||
from wagtail.wagtailimages.models import SourceImageIOError
|
||||
|
||||
|
||||
def get_rendition_or_not_found(image, specs):
|
||||
"""
|
||||
Tries to get / create the rendition for the image or renders a not-found image if it does not exist.
|
||||
|
||||
:param image: AbstractImage
|
||||
:param specs: str or Filter
|
||||
:return: Rendition
|
||||
"""
|
||||
try:
|
||||
return image.get_rendition(specs)
|
||||
except SourceImageIOError:
|
||||
# Image file is (probably) missing from /media/original_images - generate a dummy
|
||||
# rendition so that we just output a broken image, rather than crashing out completely
|
||||
# during rendering.
|
||||
Rendition = image.renditions.model # pick up any custom Image / Rendition classes that may be in use
|
||||
rendition = Rendition(image=image, width=0, height=0)
|
||||
rendition.file.name = 'not-found'
|
||||
return rendition
|
|
@ -1,7 +1,8 @@
|
|||
from django import template
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
from wagtail.wagtailimages.models import Filter, SourceImageIOError
|
||||
from wagtail.wagtailimages.models import Filter
|
||||
from wagtail.wagtailimages.shortcuts import get_rendition_or_not_found
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
@ -54,18 +55,7 @@ class ImageNode(template.Node):
|
|||
if not image:
|
||||
return ''
|
||||
|
||||
try:
|
||||
rendition = image.get_rendition(self.filter)
|
||||
except SourceImageIOError:
|
||||
# It's fairly routine for people to pull down remote databases to their
|
||||
# local dev versions without retrieving the corresponding image files.
|
||||
# In such a case, we would get a SourceImageIOError at the point where we try to
|
||||
# create the resized version of a non-existent image. Since this is a
|
||||
# bit catastrophic for a missing image, we'll substitute a dummy
|
||||
# Rendition object so that we just output a broken link instead.
|
||||
Rendition = image.renditions.model # pick up any custom Image / Rendition classes that may be in use
|
||||
rendition = Rendition(image=image, width=0, height=0)
|
||||
rendition.file.name = 'not-found'
|
||||
rendition = get_rendition_or_not_found(image, self.filter)
|
||||
|
||||
if self.output_var_name:
|
||||
# return the rendition object in the given variable
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
# -*- coding: utf-8 -*
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
from django.test import TestCase
|
||||
from django.core import serializers
|
||||
from django.conf import settings
|
||||
|
||||
from wagtail.wagtailimages.blocks import ImageChooserBlock
|
||||
|
||||
from .utils import get_test_image_file, Image
|
||||
|
||||
|
||||
class TestImageChooserBlock(TestCase):
|
||||
def setUp(self):
|
||||
self.image = Image.objects.create(
|
||||
title="Test image",
|
||||
file=get_test_image_file(),
|
||||
)
|
||||
|
||||
# Create an image with a missing file, by deserializing fom a python object
|
||||
# (which bypasses FileField's attempt to read the file)
|
||||
self.bad_image = list(serializers.deserialize('python', [{
|
||||
'fields': {
|
||||
'title': 'missing image',
|
||||
'height': 100,
|
||||
'file': 'original_images/missing-image.jpg',
|
||||
'width': 100,
|
||||
},
|
||||
'model': 'wagtailimages.image'
|
||||
}]))[0].object
|
||||
self.bad_image.save()
|
||||
|
||||
def get_image_filename(self, image, filterspec):
|
||||
"""
|
||||
Get the generated filename for a resized image
|
||||
"""
|
||||
name, ext = os.path.splitext(os.path.basename(image.file.name))
|
||||
return '{}images/{}.{}{}'.format(
|
||||
settings.MEDIA_URL, name, filterspec, ext)
|
||||
|
||||
def test_render(self):
|
||||
block = ImageChooserBlock()
|
||||
html = block.render(self.image)
|
||||
expected_html = '<img alt="Test image" src="{}" width="640" height="480">'.format(
|
||||
self.get_image_filename(self.image, "original")
|
||||
)
|
||||
|
||||
self.assertHTMLEqual(html, expected_html)
|
||||
|
||||
def test_render_missing(self):
|
||||
block = ImageChooserBlock()
|
||||
html = block.render(self.bad_image)
|
||||
expected_html = '<img alt="missing image" src="/media/not-found" width="0" height="0">'
|
||||
|
||||
self.assertHTMLEqual(html, expected_html)
|
|
@ -5,6 +5,7 @@ import unittest
|
|||
|
||||
import django
|
||||
from django.conf import settings
|
||||
from django.core import serializers
|
||||
from django.test import TestCase
|
||||
|
||||
from wagtail.wagtailcore.models import Site
|
||||
|
@ -25,6 +26,19 @@ class TestImagesJinja(TestCase):
|
|||
file=get_test_image_file(),
|
||||
)
|
||||
|
||||
# Create an image with a missing file, by deserializing fom a python object
|
||||
# (which bypasses FileField's attempt to read the file)
|
||||
self.bad_image = list(serializers.deserialize('python', [{
|
||||
'fields': {
|
||||
'title': 'missing image',
|
||||
'height': 100,
|
||||
'file': 'original_images/missing-image.jpg',
|
||||
'width': 100,
|
||||
},
|
||||
'model': 'wagtailimages.image'
|
||||
}]))[0].object
|
||||
self.bad_image.save()
|
||||
|
||||
def render(self, string, context=None, request_context=True):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
@ -64,3 +78,9 @@ class TestImagesJinja(TestCase):
|
|||
'width: {{ background.width }}, url: {{ background.url }}')
|
||||
output = ('width: 200, url: ' + self.get_image_filename(self.image, "width-200"))
|
||||
self.assertHTMLEqual(self.render(template, {'myimage': self.image}), output)
|
||||
|
||||
def test_missing_image(self):
|
||||
self.assertHTMLEqual(
|
||||
self.render('{{ image(myimage, "width-200") }}', {'myimage': self.bad_image}),
|
||||
'<img alt="missing image" src="/media/not-found" width="0" height="0">'
|
||||
)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# coding=utf-8
|
||||
from django.test import TestCase
|
||||
from wagtail.wagtailimages.shortcuts import get_rendition_or_not_found
|
||||
from .utils import Image, get_test_image_file
|
||||
|
||||
|
||||
class TestShortcuts(TestCase):
|
||||
|
||||
fixtures = ['test.json']
|
||||
|
||||
def test_fallback_to_not_found(self):
|
||||
bad_image = Image.objects.get(id=1)
|
||||
good_image = Image.objects.create(
|
||||
title="Test image",
|
||||
file=get_test_image_file(),
|
||||
)
|
||||
|
||||
rendition = get_rendition_or_not_found(good_image, 'width-400')
|
||||
self.assertEqual(rendition.width, 400)
|
||||
|
||||
rendition = get_rendition_or_not_found(bad_image, 'width-400')
|
||||
self.assertEqual(rendition.file.name, 'not-found')
|
Ładowanie…
Reference in New Issue