【问题标题】:Storing images and thumbnails on s3 in django在 django 的 s3 上存储图像和缩略图
【发布时间】:2011-08-18 03:54:03
【问题描述】:

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

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

Django + S3 (boto) + Sorl Thumbnail: Suggestions for optimisation

我正在这样做,现在看来,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 次​​p>

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

只有第 122 行的更改:

添加视图:与上面相同,除了日志记录仅显示“建立 HTTP 连接”2 次 显示视图:与上面相同,除了日志记录仅显示“建立 HTTP 连接”1 次

还在第 118 行添加更改:

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

UPDATE:貌似 storage._setup() 被调用了两次, storage.url() 被调用了一次。根据时间,我会说每个人都与 s3 建立联系:

1304711315.4
_setup
1304711317.84
1304711317.84
_setup
1304711320.3
1304711320.39
_url
1304711323.66

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

【问题讨论】:

  • 我也有同样的问题,请及时更新
  • 这有什么更新吗?另外,您在该补丁中使用什么作为 S3_UPLOAD_URL?
  • 我知道它已经很老了,但我也遇到了同样的缓慢,只是好奇是否有更新?

标签: django amazon-s3 boto sorl-thumbnail django-storage


【解决方案1】:

作为 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 并且您已正确设置键值存储。

【讨论】:

  • 感谢您的回答和出色的软件。似乎有 2 系列存储调用,每个需要 2 秒左右(我的开发服务器远离 s3 数据中心)。我添加的每一行都解决了一系列调用中的一个。我会更仔细地研究一下并再次发表评论。
【解决方案2】:

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

https://code.djangoproject.com/ticket/8307 已打开以解决此问题,但 Django 开发人员以 wontfix 的方式关闭,因为他们希望 width 和 height 属性始终返回真实值。所以我只是猴子补丁 _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

【讨论】:

【解决方案3】:

看了@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

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

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

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

【讨论】:

  • 顺便说一句:这个问题也很容易引起缩略图。
猜你喜欢
  • 1970-01-01
  • 2015-01-05
  • 2016-07-02
  • 2017-01-19
  • 2010-12-06
  • 2019-03-04
  • 1970-01-01
  • 2015-07-18
  • 2015-12-20
相关资源
最近更新 更多