Search code examples
pythondjangoioerror

django-sorl produces IOError when using template syntax


I've set up django-sorl and I truly think I'm overlooking something simple. I keep getting the following error (TEMPLATE_DEBUG = True and THUMBNAIL_DEBUG = True)

Request Method: GET Request URL: http://localhost:8000/events/edit/1

Django Version: 1.2.4 Exception Type: TemplateSyntaxError Exception Value:

Caught IOError while rendering: (2, 'No such file or directory')

Exception Location: /usr/lib/python2.6/site-packages/django/core/files/storage.py in _open, line 137

Python Executable: /usr/bin/python Python Version: 2.6.4

I'm running a redis server setup... my sorl config is:

settings.py -snip-:

TEMPLATE_DEBUG = DEBUG
THUMBNAIL_DEBUG = DEBUG
THUMBNAIL_KVSTORE = 'sorl.thumbnail.kvstores.redis_kvstore.KVStore'
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'sorl.thumbnail',
)

models.py -snip-:

from sorl.thumbnail import ImageField
...
    path = ImageField(
       _('Image'),
        upload_to='event/%Y/%m/%d/%H',
    )
...

template.html -snip-:

{% load thumbnail %}
...
{% thumbnail image "200x100" as im %}
    <img src="{{ im.url }}" alt="{{ im.name }}"/>
{% endthumbnail %}
...

I figure I'm close because files are being created on demand in the cache folder

sh> find static/cache/ -type f 
static/cache/db/ac/dbac605942d9651eb25f16cf05f5e672.jpg
static/cache/82/bc/82bcdd2ab079187c6b6110cb0e0c1505.jpg
static/cache/07/77/077784411739d4f8b1758255783388ec.jpg

When I open these files; they are the images I'm requesting on-demand. It seems to be bombing while trying to open the image to display it. Another thing to note is that if I just display the image using the following syntax it will work fine (without sorl):

working template.html (without sorl - hence... no thumbnails) -snip-:

<img src="{{ MEDIA_URL}}{{ image.path }}" alt="{{ image.name }}"/>

The key being; that I do need to prefix the {{ MEDIA_URL }} tag for the image to be present (I'm not sure if this is a factor in the error I'm getting with sorl, or just a red-herring.

Now for some final tidbits of the original error (They are from the TemplateSyntaxError page being generated - last 5).

# /var/project/src/lib/sorl/thumbnail/base.py in get_thumbnail

  36. thumbnail = ImageFile(name, default.storage)
  37. cached = default.kvstore.get(thumbnail)
  38. if cached:
  39. return cached
  40. if not thumbnail.exists():
  41. # We have to check exists() because the Storage backend does not
  42. # overwrite in some implementations.
  43. source_image = default.engine.get_image(source) ...
  44. # We might as well set the size since we have the image in memory
  45. size = default.engine.get_image_size(source_image)
  46. source.set_size(size)
  47. self._create_thumbnail(source_image, geometry_string, options,
  48. thumbnail)
  49. # If the thumbnail exists we don't create it, the other option is

▼ Local vars Variable Value cached None file_ <EventImage: TestImage> geometry_string u'200x100' key 'format' name 'cache/24/69/246986cc89951f1d37235b8f0dec0a54.jpg' options {'colorspace': 'RGB', 'crop': False, 'format': 'JPEG', 'quality': 95, 'upscale': True} self    <sorl.thumbnail.base.ThumbnailBackend object at 0x7f5b885f2c10> source <sorl.thumbnail.images.ImageFile object at 0x7f5b885c81d0> thumbnail <sorl.thumbnail.images.ImageFile object at 0x7f5b8867f510> value 'JPEG'
# /var/project/src/lib/sorl/thumbnail/engines/pil_engine.py in get_image

   5. from PIL import Image, ImageDraw
   6. except ImportError:
   7. import Image, ImageDraw
   8.
   9.
  10. class Engine(EngineBase):
  11. def get_image(self, source):

  12. buf = StringIO(source.read()) ...

  13. return Image.open(buf)
  14.
  15. def get_image_size(self, image):
  16. return image.size
  17.
  18. def dummy_image(self, width, height):

▼ Local vars Variable Value self <sorl.thumbnail.engines.pil_engine.Engine object at 0x7f5b886cf450> source <sorl.thumbnail.images.ImageFile object at 0x7f5b885c81d0>
# /home/caronc/Development/cityattention/src/lib/sorl/thumbnail/images.py in read

 114. return self._size
 115.
 116. @property
 117. def url(self):
 118. return self.storage.url(self.name)
 119.
 120. def read(self):
 121. return self.storage.open(self.name).read() ...
 122.
 123. def write(self, content):
 124. if not isinstance(content, File):
 125. content = ContentFile(content)
 126. self._size = None
 127. return self.storage.save(self.name, content)

▼ Local vars Variable Value self <sorl.thumbnail.images.ImageFile object at 0x7f5b885c81d0>
# /usr/lib/python2.6/site-packages/django/core/files/storage.py in open

  25. # These shouldn't be overridden by subclasses unless absolutely necessary.
  26.
  27. def open(self, name, mode='rb', mixin=None):
  28. """
  29. Retrieves the specified file from storage, using the optional mixin
  30. class to customize what features are available on the File returned.
  31. """
  32. file = self._open(name, mode) ...
  33. if mixin:
  34. # Add the mixin as a parent class of the File returned from storage.
  35. file.__class__ = type(mixin.__name__, (mixin, file.__class__), {})
  36. return file
  37.
  38. def save(self, name, content):

▼ Local vars Variable Value mixin None mode 'rb' name u'TestImage' self      <django.core.files.storage.FileSystemStorage object at 0x7f5b8867f3d0>
# /usr/lib/python2.6/site-packages/django/core/files/storage.py in _open

 130. location = settings.MEDIA_ROOT
 131. if base_url is None:
 132. base_url = settings.MEDIA_URL
 133. self.location = os.path.abspath(location)
 134. self.base_url = base_url
 135.
 136. def _open(self, name, mode='rb'):
 137. return File(open(self.path(name), mode)) ...
 138.
 139. def _save(self, name, content):
 140. full_path = self.path(name)
 141.
 142. directory = os.path.dirname(full_path)
 143. if not os.path.exists(directory):

▼ Local vars Variable Value mode 'rb' name u'TestImage' self <django.core.files.storage.FileSystemStorage object at 0x7f5b8867f3d0>

I unsuccessfully Googled for this error; I'm hoping that my problem is just a quick one since everything is working except the template display.


Solution

  • The documentation was a bit weak in this field, but after importing the python debugger, I was able to find out where the problem was.

    There are 2 potential solutions to this issue. The first one that fixed everything for me was to alter my template to read:

    {% load thumbnail %}
    ...
    {% thumbnail image.path "200x100" as im %}
        <img src="{{ im.url }}" alt="{{ im.name }}"/>
    {% endthumbnail %}
    ...
    

    I'm guessing the issue still may be at my end; especially since this tool has been bulletproof for some time now. That said, those who are experiencing the same issue will need to add the .path argument to save themselves the grief I went through.

    An alternative (not a very good one) option is to add this to your models.py and then reference the image directly again (as I did in my initial question).

    def __unicode__(self):
        return self.image.path
    

    This of course is a nasty solution if the object containing the event your trying to display is not solely responsible for displaying images. Hence... the second option may only be ideal in 'some' situations. I'd stick with the first workaround.

    This work-around is applicable to the 10.12.1 patch.

    Also, to justify my initial question. I stated that static images were being created; as it turns out, this was incorrect. Although those images 'were' the correct thumbnails of the images I couldn't get to work on my page. They were being automatically generated from the DJango-Admin tool. Probably back when I was trying to upload different images (tackling the problem the wrong way). :)