如何解决保存任何缩略图的转换引擎问题
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,**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',editable=False)
owner = models.ForeignKey('api_backend.User',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]
文件字段实际上可以是任何文件,我希望 sorl-thumbnail 为其制作缩略图并将其保存到缩略图字段中。我在 Windows 上并且正在使用 ImageMagick。 [python 版本 - 32 位]
这是我安装的二进制发行版。 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'
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\iyapp\\PycharmProjects\\reBox\\media\\cache\\db\\5a\\db5a88e1d6a08cdfa1afbc92e9b8cb47.jpg'
完整回溯:
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,**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,**kwargs)
File "C:\Users\iyapp\Envs\reBox_django\lib\site-packages\rest_framework\generics.py",line 242,in post
return self.create(request,**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,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'
有人可以帮我解决这个问题吗? 非常感谢!
解决方法
据我所知,这就是第一个异常出现的原因。
from django.core.files.temp import NamedTemporaryFile
https://github.com/jazzband/sorl-thumbnail/blob/master/sorl/thumbnail/engines/convert_engine.py#L8 此导入返回一个 TemporaryFile (见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,tb)
NamedTemporaryFile = TemporaryFile
else:
NamedTemporaryFile = tempfile.NamedTemporaryFile
gettempdir = tempfile.gettempdir
TemporayFile 类的 init 方法不接受任何名为 delete
的参数。相反,只有 tempfile.NamedTemporaryFile
可以。因此,这块代码失败了。
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
我认为正因为如此,文件根本没有被保存。 最后,在模型的保存方法中,
我们看到后端提出文件不存在。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。