【问题标题】:sorl-thumbnail won't delete thumbnailssorl-thumbnail 不会删除缩略图
【发布时间】:2011-07-01 15:06:41
【问题描述】:

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']])

【问题讨论】:

    标签: django sorl-thumbnail


    【解决方案1】:

    这有点难以解释,所以我做了这张很棒的桌子。下面列出了第一列的命令,其他列使用 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 中更改了删除行为,请参阅发行说明。

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

    【讨论】:

    • 感谢伟大的桌子,它帮助证实了我的理解。我有生成文件名的代码,如果该名称的文件已经存在,则将其删除,以便它可能以某种方式被覆盖。如前所述,我尝试了您提到的前两种方法,但效果为零。我希望缩略图缓存被键入文件数据而不仅仅是文件名,并且会删除过时的缩略图或至少在覆盖同名文件时创建新的缩略图。我的新基于哈希的后端通过在文件更改时创建新缩略图来解决此问题。
    • 使用文件数据的解决方案的问题在于,这是一个非常昂贵的操作,因为每次请求缩略图时都需要在内存中打开整个文件。我对上表中的命令进行了工作测试,所以我真的不明白为什么它会在你这边失败,也许你可以使用像 pdb 这样的调试器在一些明智选择的断点处获取更多信息。也许您正在重新生成缩略图(从旧图像)并因此在使用 sorl.thumbnail.delete 删除它们后更新键值存储?
    • 我认为可能存在一些问题,即数据库没有在您的时间范围内更新,有一个待处理的事务(如果您使用的是缓存的数据库键值存储)但即使这是问题sorl.thumbnail.delete 仍然会删除缩略图文件。如果删除后缩略图文件仍然存在,则您正在重新生成它们,假设您具有删除文件的权限。
    【解决方案2】:

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

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

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

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

    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 答案。希望它可以帮助某人:)

    【讨论】:

    • 我猜这是假设您使用的是 Django。也许你不是:|
    【解决方案3】:

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

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

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

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

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

    其中imagemodels.ImageField 实例,但使用其file 属性:

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

    并在你的Python代码中删除它(下面是Storage的一个例子,如果名称相同,覆盖现有文件):

    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 中的错误,或者是否有充分的理由生成不同的密钥。

    【讨论】:

      【解决方案4】:

      我看到了这个问题。这是因为 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_thumbnail 名称参数更改为 self.picture.name

      【讨论】:

        猜你喜欢
        • 2012-09-18
        • 2015-06-14
        • 2012-06-12
        • 2016-05-10
        • 2019-10-14
        • 2011-02-13
        • 2011-02-03
        • 2012-03-06
        • 1970-01-01
        相关资源
        最近更新 更多