So I have a model like this
from django.db import models
from sorl.thumbnail import get_thumbnail
class Upload(BaseModel):
@staticmethod
def upload_path_handler(instance, filename):
return f'boxes/{instance.box.id}/uploads/{filename}'
@staticmethod
def thumbnail_path_handler(instance, filename):
return f'boxes/{instance.box.id}/thumbnails/{filename}'
def save(self, *args, **kwargs):
if self._state.adding:
# we cache the file size and store
# it into the database to improve performance
# we cannot edit the object's file so we don't
# bother to modify the file size on updates
self.size = self.file.size
super(Upload, self).save(*args, **kwargs)
thumbnail = get_thumbnail(self.file, '1280x720', crop='center')
# sorl is not saving the thumbnails for non-image files
return self.thumbnail.save(thumbnail.name, ContentFile(thumbnail.read()), True)
super(Upload, self).save(*args, **kwargs)
objects = api_managers.UploadManager()
size = models.PositiveBigIntegerField()
name = models.CharField(max_length=100, default='untitled', validators=[MinLengthValidator(2)])
channel = models.ForeignKey('api_backend.Channel', on_delete=models.CASCADE, editable=False)
box = models.ForeignKey('api_backend.Box', on_delete=models.CASCADE, editable=False)
owner = models.ForeignKey('api_backend.User', on_delete=models.CASCADE, editable=False)
thumbnail = models.ImageField(max_length=512, upload_to=thumbnail_path_handler.__func__, null=True, blank=True)
file = models.FileField(max_length=512, upload_to=upload_path_handler.__func__)
REQUIRED_FIELDS = [file, owner]
the file field can be literally any file, and I want sorl-thumbnail to make a thumbnail for the same and save it into the thumbnail field. I am on windows and am using ImageMagick. [python version- 32 bits]
this is the binary distribution I installed. https://imagemagick.org/script/download.php
ImageMagick-7.0.10-61-Q16-x86-dll.exe Win32 dynamic at 16 bits-per-pixel component
settings.py
THUMBNAIL_ENGINE = 'sorl.thumbnail.engines.convert_engine.Engine'
However, whenever an upload-model is saved, I get the following error.
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\iyapp\\PycharmProjects\\rebox\\media\\cache\\db\\5a\\db5a88e1d6a08cdfa1afbc92e9b8cb47.jpg'
Full traceback:
Exception ignored in: <function TemporaryFile.__del__ at 0x04184610>
Traceback (most recent call last):
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\django\core\files\temp.py", line 61, in __del__
self.close()
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\django\core\files\temp.py", line 49, in close
if not self.close_called:
AttributeError: 'TemporaryFile' object has no attribute 'close_called'
__init__() got an unexpected keyword argument 'delete'
Traceback (most recent call last):
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\sorl\thumbnail\base.py", line 104, in get_thumbnail
source_image = default.engine.get_image(source)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\sorl\thumbnail\engines\convert_engine.py", line 76, in get_image
with NamedTemporaryFile(mode='wb', delete=False) as fp:
TypeError: __init__() got an unexpected keyword argument 'delete'
Remote file [boxes/2/uploads/a243bfbd00fdcb54982faf63cfc290b1dfcd47f1c0484facbd67c8b8ff606aff.jpg] at [1280x720] does not exist
exc: [Errno 2] No such file or directory: 'C:\\Users\\iyapp\\PycharmProjects\\rebox\\media\\cache\\db\\5a\\db5a88e1d6a08cdfa1afbc92e9b8cb47.jpg'
Internal Server Error: /api/channels/1/uploads/
Traceback (most recent call last):
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\asgiref\sync.py", line 339, in thread_handler
raise exc_info[1]
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\django\core\handlers\exception.py", line 38, in inner
response = await get_response(request)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\django\core\handlers\base.py", line 233, in _get_response_async
response = await wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\asgiref\sync.py", line 304, in __call__
ret = await asyncio.wait_for(future, timeout=None)
File "c:\python38\lib\asyncio\tasks.py", line 455, in wait_for
return await fut
File "c:\python38\lib\concurrent\futures\thread.py", line 57, in run
result = self.fn(*self.args, **self.kwargs)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\asgiref\sync.py", line 343, in thread_handler
return func(*args, **kwargs)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\django\views\generic\base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\rest_framework\views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
raise exc
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\rest_framework\views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\rest_framework\generics.py", line 242, in post
return self.create(request, *args, **kwargs)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\rest_framework\mixins.py", line 19, in create
self.perform_create(serializer)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\rest_framework\mixins.py", line 24, in perform_create
serializer.save()
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\rest_framework\serializers.py", line 205, in save
self.instance = self.create(validated_data)
File "C:\Users\iyapp\PycharmProjects\rebox\api_backend\serializers\partial.py", line 35, in create
return super(PartialUploadSerializer, self).create(validated_data)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\rest_framework\serializers.py", line 939, in create
instance = ModelClass._default_manager.create(**validated_data)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\django\db\models\query.py", line 447, in create
obj.save(force_insert=True, using=self.db)
File "C:\Users\iyapp\PycharmProjects\rebox\api_backend\models\uploads.py", line 43, in save
return self.thumbnail.save(thumbnail.name, ContentFile(thumbnail.read()), True)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\sorl\thumbnail\images.py", line 162, in read
f = self.storage.open(self.name)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\django\core\files\storage.py", line 36, in open
return self._open(name, mode)
File "C:\Users\iyapp\Envs\rebox_django\lib\site-packages\django\core\files\storage.py", line 231, in _open
return File(open(self.path(name), mode))
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\iyapp\\PycharmProjects\\rebox\\media\\cache\\db\\5a\\db5a88e1d6a08cdfa1afbc92e9b8cb47.jpg'
Can someone please help me fix this? thanks a lot!
as far as I know this is why the first exception arises.
from django.core.files.temp import NamedTemporaryFile
https://github.com/jazzband/sorl-thumbnail/blob/master/sorl/thumbnail/engines/convert_engine.py#L8 this import returns a TemporaryFile (see source code)
"""
The temp module provides a NamedTemporaryFile that can be reopened in the same
process on any platform. Most platforms use the standard Python
tempfile.NamedTemporaryFile class, but Windows users are given a custom class.
This is needed because the Python implementation of NamedTemporaryFile uses the
O_TEMPORARY flag under Windows, which prevents the file from being reopened
if the same flag is not provided [1][2]. Note that this does not address the
more general issue of opening a file for writing and reading in multiple
processes in a manner that works across platforms.
The custom version of NamedTemporaryFile doesn't support the same keyword
arguments available in tempfile.NamedTemporaryFile.
1: https://mail.python.org/pipermail/python-list/2005-December/336957.html
2: https://bugs.python.org/issue14243
"""
import os
import tempfile
from django.core.files.utils import FileProxyMixin
__all__ = ('NamedTemporaryFile', 'gettempdir',)
if os.name == 'nt':
class TemporaryFile(FileProxyMixin):
"""
Temporary file object constructor that supports reopening of the
temporary file in Windows.
Unlike tempfile.NamedTemporaryFile from the standard library,
__init__() doesn't support the 'delete', 'buffering', 'encoding', or
'newline' keyword arguments.
"""
def __init__(self, mode='w+b', bufsize=-1, suffix='', prefix='', dir=None):
fd, name = tempfile.mkstemp(suffix=suffix, prefix=prefix, dir=dir)
self.name = name
self.file = os.fdopen(fd, mode, bufsize)
self.close_called = False
# Because close can be called during shutdown
# we need to cache os.unlink and access it
# as self.unlink only
unlink = os.unlink
def close(self):
if not self.close_called:
self.close_called = True
try:
self.file.close()
except OSError:
pass
try:
self.unlink(self.name)
except OSError:
pass
def __del__(self):
self.close()
def __enter__(self):
self.file.__enter__()
return self
def __exit__(self, exc, value, tb):
self.file.__exit__(exc, value, tb)
NamedTemporaryFile = TemporaryFile
else:
NamedTemporaryFile = tempfile.NamedTemporaryFile
gettempdir = tempfile.gettempdir
and the TemporayFile class' init method doesn't take any parameter named delete
. instead, only tempfile.NamedTemporaryFile
does. Therefore, this chunk of code fails.
def get_image(self, source):
"""
Returns the backend image objects from a ImageFile instance
"""
with NamedTemporaryFile(mode='wb', delete=False) as fp:
fp.write(source.read())
return {'source': fp.name, 'options': OrderedDict(), 'size': None}
https://github.com/jazzband/sorl-thumbnail/blob/master/sorl/thumbnail/engines/convert_engine.py#L72
I think that because of this the file isn't being saved at all. And at last, inside the save method of the model,
We see the backend raise that the file doesn't exist.