25

我正在尝试使用 django-storages、boto 和 sorl-thumbnail 将我的图像缩略图并存储在 s3 上。我有它的工作,但它很慢,即使是小图像。我不介意保存表单并将图像上传到 s3 时速度很慢,但我希望它在此之后快速显示图像。

这个 SO question 的答案解释说,在第一次访问之前不会创建缩略图,但您可以使用 get_thumbnail() 预先创建它。

Django + S3 (boto) + Sorl Thumbnail: 优化建议

我正在这样做,现在似乎 thumbnail_kvstore 表中的所有条目都是在上传图像时创建的,而不是在显示时创建的。

问题是显示图像的页面仍然很慢。查看调试工具栏中的日志记录面板,看起来与 s3 的通信仍然很多。似乎在上传和缓存图像和缩略图后,页面应该快速呈现而不与 s3 通信。

我究竟做错了什么?谢谢!

更新:weak hack 似乎已经让它工作了,但我很想知道如何正确地做到这一点:

https://github.com/asciitaxi/sorl-thumbnail/commit/545cce3f5e719a91dd9cc21d78bb973b2211bbbf

更新:@sorl 的更多信息

我正在使用 2 个视图:

添加视图:在此视图中,我提交表单以创建包含图像的模型。图片上传到s3。在 post_save 信号中,我调用 get_thumbnail() 在需要之前生成缩略图:

im = get_thumbnail(instance.image, '360x360')

显示视图:在此视图中,我显示在添加视图中生成的缩略图:

    {% thumbnail object.image "360x360" as im %}
    <img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}">
    {% endthumbnail %}

没有补丁:

添加视图:在 kvstore 表中创建 3 个条目,访问缓存 10 次(6 组,4 次获取),调试工具栏的日志记录选项卡显示“建立 HTTP 连接”12 次

显示视图:kvstore 表中仍然只有 3 个条目,只有 1 个从缓存中获取,但调试工具栏仍然显示“建立 HTTP 连接”3 次

只有第 122 行的更改:

添加视图:同上,除了日志只说“建立 HTTP 连接”2 次 显示视图:同上,除了日志只说“建立 HTTP 连接”1 次

还在第 118 行添加更改:

添加视图:与上面相同,但现在我们减少到 2 条“建立 HTTP 连接”消息 显示视图:与上面相同,根本没有日志消息

更新:看起来 storage._setup() 被调用了两次, storage.url() 被调用了一次。根据时间,我会说每个人都与 s3 建立连接:

1304711315.4
_setup
1304711317.84
1304711317.84
_setup
1304711320.3
1304711320.39
_url
1304711323.66

这似乎反映在 boto 日志记录中,它说“建立 HTTP 连接”3 次。

4

3 回答 3

7

作为 sorl thumbnail 的作者,如果它没有按我的预期工作,我真的很想解决这个问题。如果键值 sotre 被填充,它将当前存储:名称、存储和大小。我假设 url 是基于名称的,因此不应导致任何存储调用。查看 django 存储,https://github.com/e-loue/django-storages/blob/master/storages/backends/s3boto.py#L214这似乎是一个安全的假设。在您的补丁中,您出于某种原因修补了 read 方法。创建缩略图时,会从缓存中获取 ImageFile 实例(如果不创建它),那么您当然可以调用 read 来读取文件,但预期用途是 .url ,它使用缓存名称调用存储上的 url 反过来应该是一个非存储访问操作。您能否尝试将您的问题隔离到代码中此存储访问发生的确切位置?

还要确保您已打开 THUMBNAIL_DEBUG 并且您已正确设置键值存储。

于 2011-05-05T19:47:44.790 回答
2

我不确定您的问题是否与我的相同,但我发现访问普通 Django ImageField 的 width 或 height 属性将从存储后端读取文件,将其加载到 PIL 中,然后从那里返回尺寸。对于我们正在使用的远程后端,这尤其昂贵,而且我们有非常多的媒体页面。

https://code.djangoproject.com/ticket/8307已打开以解决此问题,但 Django 开发人员以 wontfix 的方式关闭,因为他们希望 width 和 height 属性始终返回真实值。所以我只是monkeypatch _get_image_dimensions() 来使用这些字段,这确实可以防止大量的boto 消息并缩短我的页面加载时间。

下面是我从附在该票证上的补丁修改的代码。我把它放在了一个早期执行的地方,比如models.py。

from django.core.files.images import ImageFile, get_image_dimensions
def _get_image_dimensions(self):
    from numbers import Number
    if not hasattr(self, '_dimensions_cache'):
        close = self.closed
        if self.field.width_field and self.field.height_field:
            width = getattr(self.instance, self.field.width_field)
            height = getattr(self.instance, self.field.height_field)
            #check if the fields have proper values
            if isinstance(width, Number) and isinstance(height, Number):
                self._dimensions_cache = (width, height)
            else:
                self.open()
                self._dimensions_cache = get_image_dimensions(self, close=close)
        else:
            self.open()
            self._dimensions_cache = get_image_dimensions(self, close=close)

    return self._dimensions_cache
ImageFile._get_image_dimensions = _get_image_dimensions
于 2011-09-09T14:50:41.340 回答
0

看了@shadfc django票后,我重新实现了monkeypatch如下:

from django.core.files.images import ImageFile
def _get_image_dimensions(self):
    if not hasattr(self, '_dimensions_cache'):
        if getattr(self.storage, 'IGNORE_IMAGE_DIMENSIONS', False):
            self._dimensions_cache = (0, 0)
        else:
            close = self.closed
            self.open()
            self._dimensions_cache = get_image_dimensions(self, close=close)
    return self._dimensions_cache
ImageFile._get_image_dimensions = _get_image_dimensions

要使用它,只需将 a 添加IGNORE_IMAGE_DIMENSIONS = True到您的存储类中,就不会触及它来获取图像尺寸。可能:

from storages.backends.s3boto import S3BotoStorage
S3BotoStorage.IGNORE_IMAGE_DIMENSIONS = True

我仍然需要调查这些数字的使用位置,以了解简单的返回是否(0, 0)会导致任何问题,但目前没有出现错误。

于 2012-01-13T21:23:57.033 回答