sorl-thumbnail 不会删除缩略图

发布于 2024-10-18 09:13:53 字数 1457 浏览 0 评论 0原文

SORL 缩略图存在问题,并在文件被覆盖时删除缩略图文件或刷新缩略图。情况是我有一个文件,每个条目始终相同但可以被覆盖。上传新文件并覆盖旧文件时需要重新创建缩略图。

这是在模型 + 表单级别,因此我使用低级别 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']])

Having issues with SORL Thumbnail and deleting thumbnails files or refreshing thumbnails when a file is overwritten. The scenario is that I have a file that for each entry is always the same but can be overwritten. Need the thumbnail to be recreated when a new file is uploaded and the old file is overwritten.

This is at the model + form level so I'm using the low level API to generate thumbs.

Have tried using:

from sorl.thumbnail import delete

delete(filename)

But with no success, the thumbnail is never deleted or overwritten.

I have even tried:

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

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

Again with no success.

Please help!

Update:

I found a work around by creating an alternate ThumbnailBackend and a new _get_thumbnail_filename method. The new method uses a file's SHA-1 hash to always have a thumbnail specific to the current file.

Here's the backend for anyone else that might encounter a similar scenario.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

紫竹語嫣☆ 2024-10-25 09:13:53

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

| Command | Original | Thumbnails | KV Original | KV Thumbnails |
| #1      | X        | X          | X           | X             |
| #2      |          | X          |             | X             |
| #3      |          | X          | X           | X             |
  1. sorl.thumbnail.delete(文件名)
  2. sorl.thumbnail.default.kvstore.delete_thumbnails(image_file)
  3. sorl.thumbnail.delete(文件名,delete_file=False)< /code>

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

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

Its a little hard to explain so I made this awesome table. the first column's commands are listed below, the other columns marks wheter it deletes using an X. Original is the original file, thumbnails the thumbnails for the original and KV means the Key Value store reference.

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

As I understand it you really want to do #3. Now, your problem... a guess is that filename does not refer to a filename relative to MEDIA_ROOT (if you are using another storage backend the situation would be similar). But I think I need to know what you are doing besides this to get a better picture, note that ImageFields and FileFields do not overwrite, also note that django changed the deletion behaviour in 1.2.5, see release notes.

Update:
Anyone reading this should note that the above way to generate thumbnail filenames is extremely inefficient, please do not use if you care anything at about performance.

ゞ花落谁相伴 2024-10-25 09:13:53

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

我有一个带有 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 缩略图清理和 ./manage.py 缩略图清除之后,我也无法让 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()

这是我的第一个答案。希望它对某人有帮助:)

I'm not completely sure whether this answers your question, but I was having the same problem and this was my solution.

I have a model with a FileField on it, like such:

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

When handling an uploaded file, I use get_thumbnail() to generate the thumbnail, passing the FileField in as the parameter vs the python level file behind it. ie:

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

As with your issue, I also found that when a file had the same name, sorl would just grab the thumbnail from the cache instead of generating a new one. Aggravating!

What worked was using sorl's delete method and passing the FileField. I first tried passing in the python file behind the FileField object, which is possibly what you were trying? Going from this:

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

To this:

sorl.thumbnail.delete(modelinstance.material)

Seemed to line up with sorl-thumbnail's KV Store, and would properly get the cached thumbnail out of the way so the new one could be created from the new file. Yay!

This was helpful for me: http://sorl-thumbnail.readthedocs.org/en/latest/operation.html

Also, even after running ./manage.py thumbnail cleanup and ./manage.py thumbnail clear, I couldn't get Django to stop looking for the old thumbnails in the same place. I had to manually clear the Django cache (I'm using memcached). Here's how you can do that:

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()

This is my first SO answer. Hope it helps someone :)

飞烟轻若梦 2024-10-25 09:13:53

问题是,您不能将快捷方式 delete(file) 与 File 类一起使用,该 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代码中(以下是存储的示例,如果名称相同,则覆盖现有文件):

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

The thing is you cannot use the shortcut delete(file) with a File class that is different to the one you employed to generate that very thumbnail through get_thumbnail() or the {% thumbnail ...%} templatetag.

The reason is ImageFile instances constructed from the file objects will get differents keys (ImageFile.key) and delete() will never be able to retrieve the good thumbnails to remove because the keys don't match.

I'm not sure that it won't works if you use a Python File object and then a Django File object for instance, but in Django, if you generate the thumbnail with a FileField object and try to delete it (and its thumbnails) with a File instance, it will not works for sure.

So, in your templates, don't do:

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

Where image is a models.ImageField instance, but use its file attribute:

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

And to delete it in your Python code (the following is an example of Storage to overwrite the existing file if the name is the same):

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)

Not sure if its a bug in sorl or if there is a good reason to generate different keys.

拥抱没勇气 2024-10-25 09:13:53

我看到了这个问题。发生这种情况是因为 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

I saw this problem. It was happening because Sorl was being used oddly.

All the thumbnail were got in the following style:

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

And when deleting the thumbnail (removing them from cache) it was being done like this:

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

Shortly, we were using the image's URL to generate and fetch the thumbnails, and when deleting we were using the image's name. Although Sorl didn't complain about it, the KV Store and the FS weren't never cleaned up.

The fix was to just change the get_thumbnail name argument to self.picture.name.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文