4

SORL Thumbnail 出现问题并在文件被覆盖时删除缩略图文件或刷新缩略图。场景是我有一个文件,每个条目总是相同但可以被覆盖。上传新文件并覆盖旧文件时需要重新创建缩略图。

这是在模型 + 表单级别,所以我使用低级 API 来生成拇指。

尝试过使用:

from sorl.thumbnail import delete

delete(filename)

但是没有成功,缩略图永远不会被删除或覆盖。

我什至尝试过:

from sorl.thumbnail.images import ImageFile
from sorl.thumbnail import default

image_file = ImageFile(filename)
default.kvstore.delete_thumbnails(image_file)

再次没有成功。

请帮忙!

更新:

我通过创建一个备用 ThumbnailBackend 和一个新的 _get_thumbnail_filename 方法找到了解决方法。新方法使用文件的 SHA-1 哈希来始终拥有特定于当前文件的缩略图。

这是可能遇到类似情况的其他任何人的后端。

class HashThumbnailBackend(ThumbnailBackend):
  
  def _get_thumbnail_filename(self, source, geometry_string, options):
    """
    Computes the destination filename.
    """
    import hashlib
    
    # hash object
    hash = hashlib.sha1()
    
    # open file and read it in as chunks to save memory
    f = source.storage.open(u'%s' % source, 'rb')
    while True:
      chunk = f.read(128)
      if not chunk:
        break
      hash.update(hashlib.sha1(chunk).hexdigest())
    
    # close file
    f.close()
    
    hash.update(geometry_string)
    hash.update(serialize(options))
    key = hash.hexdigest()
    
    # make some subdirs
    path = '%s/%s/%s' % (key[:2], key[2:4], key)
    return '%s%s.%s' % (settings.THUMBNAIL_PREFIX, path,
                        self.extensions[options['format']])
4

4 回答 4

17

这有点难以解释,所以我做了这张很棒的桌子。下面列出了第一列的命令,其他列使用 X 标记是否删除。 Original 是原始文件,缩略图是原始文件的缩略图,KV 表示键值存储引用。

| Command | Original | Thumbnails | KV Original | KV Thumbnails |
| #1      | X        | X          | X           | X             |
| #2      |          | X          |             | X             |
| #3      |          | X          | X           | X             |
  1. sorl.thumbnail.delete(filename)
  2. sorl.thumbnail.default.kvstore.delete_thumbnails(image_file)
  3. sorl.thumbnail.delete(filename, delete_file=False)

据我了解,你真的想做#3。现在,你的问题......猜测是它filename不引用相对于的文件名MEDIA_ROOT(如果你使用另一个存储后端,情况会相似)。但我想我需要知道除此之外你在做什么以获得更好的图片,请注意 ImageFields 和 FileFields 不会覆盖,还请注意 django 在 1.2.5 中更改了删除行为,请参阅发行说明。

更新:任何阅读本文的人都应该注意,上述生成缩略图文件名的方法效率极低,如果您关心性能,请不要使用。

于 2011-02-23T00:08:49.860 回答
6

我不完全确定这是否回答了你的问题,但我遇到了同样的问题,这是我的解决方案。

我有一个带有 FileField 的模型,如下所示:

material = models.FileField(upload_to='materials')

在处理上传的文件时,我使用 get_thumbnail() 生成缩略图,将 FileField 作为参数传入,而不是它后面的 python 级别文件。IE:

thumb = get_thumbnail(modelinstance.material, '%dx%d' % (thumb_width, thumb_height))

与您的问题一样,我还发现当文件具有相同名称时, sorl 只会从缓存中获取缩略图,而不是生成新的。加重!

起作用的是使用 sorl 的删除方法并传递 FileField。我首先尝试在 FileField 对象后面传递 python 文件,这可能是你正在尝试的?从这里开始:

sorl.thumbnail.delete(modelinstance.material.file)

对此:

sorl.thumbnail.delete(modelinstance.material)

似乎与 sorl-thumbnail 的 KV 存储一致,并且会正确地让缓存的缩略图不碍事,以便可以从新文件中创建新的缩略图。耶!

这对我很有帮助:http ://sorl-thumbnail.readthedocs.org/en/latest/operation.html

此外,即使在运行 ./manage.py thumbnail cleanup 和 ./manage.py thumbnail clear 之后,我也无法让 Django 停止在同一个地方寻找旧的缩略图。我不得不手动清除 Django 缓存(我正在使用 memcached)。您可以这样做:

import os

# Set the DJANGO_SETTINGS_MODULE environment variable.
os.environ['DJANGO_SETTINGS_MODULE'] = "yourproject.settings"

from django.core.cache import cache

# Flush!
cache._cache.flush_all()

这是我的第一个 SO 答案。希望它可以帮助某人:)

于 2012-11-15T23:21:32.567 回答
1

我看到了这个问题。它正在发生,因为Sorl被奇怪地使用了。

所有缩略图均采用以下样式:

sorl.thumbnail.get_thumbnail(self.picture.url, geometry_string, **options)
# picture being a FieldFile

当删除缩略图(从缓存中删除它们)时,它是这样完成的:

sorl.thumbnail.delete(self.picture.name, delete_files=False)

很快,我们使用图像的URL来生成和获取缩略图,并且在删除时我们使用了图像的名称。虽然Sorl没有抱怨,但 KV Store 和 FS 并没有被清理干净。

解决方法是将get_thumbnailname 参数更改为self.picture.name.

于 2014-09-04T21:16:07.513 回答
1

问题是您不能将快捷方式delete(file)与 File 类一起使用,该类与您用来生成该缩略图或模板标签的类不同。get_thumbnail(){% thumbnail ...%}

原因是从文件对象构造的 ImageFile 实例将获得不同的键 (ImageFile.key) 并且 delete() 将永远无法检索要删除的好缩略图,因为键不匹配。

File例如,如果您使用 Python对象然后使用 Django对象,我不确定它是否不起作用File,但是在 Django 中,如果您使用对象生成缩略图并尝试使用实例FileField删除它(及其缩略图)File,它肯定不会起作用。

所以,在你的模板中,不要这样做:

{% load thumbnail %}
{% thumbnail image "100" as im %}
<img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}">
{% endthumbnail %}

实例在哪里,但使用它image的属性:models.ImageFieldfile

{% load thumbnail %}
{% thumbnail image.file "100" as im %}

并在您的 Python 代码中将其删除(以下是存储在名称相同的情况下覆盖现有文件的示例):

from django.core.files.storage import FileSystemStorage
from django.core.files import File
from sorl.thumbnail import delete


class OverwriteStorage(FileSystemStorage):
    def _save(self, name, content):
        if self.exists(name):
            img = File(open(os.path.join(self.location, name), "w"))
            delete(img)
        return super(OverwriteStorage, self)._save(name, content)

不确定它是否是 sorl 中的错误,或者是否有充分的理由生成不同的密钥。

于 2013-04-26T13:38:01.303 回答