25

django-storages、boto、および sorl-thumbnail を使用して、画像をサムネイル化し、s3 に保存しようとしています。動作していますが、小さな画像でも非常に遅いです。フォームを保存してs3に画像をアップロードするときは遅くても構わないのですが、その後は早く画像を表示してほしいです。

この SO の質問に対する回答では、サムネイルは最初のアクセスまで作成されませんが、get_thumbnail() を使用して事前に作成できることが説明されています。

Django + S3 (boto) + Sorl Thumbnail: 最適化の提案

私はそれをやっていますが、画像が表示されるときではなく、画像をアップロードするときに、thumbnail_kvstore テーブルへのすべてのエントリが作成されるようです。

問題は、画像を表示するページがまだ非常に遅いことです。デバッグ ツールバーのログ パネルを見ると、s3 との通信がまだたくさんあるようです。画像とサムネイルがアップロードされてキャッシュされた後、s3 と通信せずにページがすばやくレンダリングされるようです。

私は何を間違っていますか?ありがとう!

更新:弱いハックでうまくいったようですが、これを適切に行う方法を知りたいです:

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

更新: @sorl の詳細情報

私は2つのビューで作業しています:

ADD VIEW: このビューでは、フォームを送信して、画像を含むモデルを作成します。画像は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行目の変更のみ:

ADD VIEW: 上記と同じですが、ログに「HTTP 接続の確立」のみが 2 回表示されます DISPLAY VIEW: 上記と同じですが、ログに「HTTP 接続の確立」と 1 回のみ表示されます

また、118 行目に変更を追加します。

ADD VIEW: 上記と同じですが、「HTTP 接続を確立しています」というメッセージが 2 つになりました DISPLAY VIEW: 上記と同じで、ログ メッセージはまったくありません

更新: storage._setup() が 2 回呼び出され、storage.url() が 1 回呼び出されたようです。タイミングに基づいて、それぞれが s3 に接続していると思います。

1304711315.4
_setup
1304711317.84
1304711317.84
_setup
1304711320.3
1304711320.39
_url
1304711323.66

これは、「HTTP 接続を確立しています」と 3 回表示される boto ロギングに反映されているようです。

4

3 に答える 3

7

sorl サムネイルの作成者として、意図したとおりに機能しない場合は、これを解決することに本当に興味があります。キー値 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 の幅または高さのプロパティにアクセスすると、ストレージ バックエンドからファイルが読み取られ、PIL に読み込まれ、そこから寸法が返されることがわかりました。これは、私たちが使用しているようなリモート バックエンドでは特にコストがかかり、非常にメディアの多いページがあります。

https://code.djangoproject.com/ticket/8307はこれに対処するために開かれましたが、Django 開発者は幅と高さのプロパティが常に真の値を返すことを望んでいるため、wontfix として閉じました。そのため、これらのフィールドを使用するために _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チケットを見た後、次のようにモンキーパッチを再実装しました。

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)、現時点ではバグは発生していません。

于 2012-01-13T21:23:57.033 に答える