web-dev-qa-db-ja.com

Django)を使用したAmazonS3への非同期ファイルのアップロード

私はこのファイルストレージエンジンを使用して、ファイルがアップロードされたときにAmazonS3にファイルを保存しています。

http://code.welldev.org/Django-storages/wiki/Home

応答がクライアントに返される前に、ファイルを最初にクライアントからWebサーバーにアップロードし、次にWebサーバーをAmazon S3にアップロードする必要があるため、アップロードにはかなり長い時間がかかります。

ファイルをS3に送信するプロセスを非同期にして、応答をユーザーにはるかに速く返すことができるようにしたいと思います。ファイルストレージエンジンでこれを行うための最良の方法は何ですか?

アドバイスをしてくれてありがとう!

35
Andrew C

私はこの問題に対して別のアプローチを取りました。

私のモデルには2つのファイルフィールドがあり、1つは標準のファイルストレージバックエンドを使用し、もう1つはs3ファイルストレージバックエンドを使用します。ユーザーがファイルをアップロードすると、そのファイルはローカルに保存されます。

アプリケーションに、ローカルに保存されているすべてのファイルをs3にアップロードし、モデルを更新する管理コマンドがあります。

そのため、ファイルのリクエストが来たら、モデルオブジェクトがs3ストレージフィールドを使用しているかどうかを確認します。使用している場合は、s3の正しいURLにリダイレクトを送信します。使用していない場合は、nginxがディスクからファイルを提供できるようにリダイレクトを送信します。 。

もちろん、この管理コマンドは、cronjobなどのイベントによってトリガーできます。

24
Vasil

特別なフォーム(非表示フィールドに暗号化されたポリシードキュメントを使用)を使用して、ユーザーがブラウザーからS3にファイルを直接アップロードするようにすることができます。アップロードが完了すると、アプリケーションにリダイレクトされます。

詳細はこちら: http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1434

22
Simon Willison

そのためのアプリがあります:-)

https://github.com/jezdez/Django-queued-storage

「ローカル」ストレージと「リモート」ストレージを設定できるため、必要なことを正確に実行できます。このアプリは、ファイルを高速の「ローカル」ストレージ(MogileFSストレージなど)に保存し、 Celery (Django-celery)を使用して、「リモート」ストレージへの非同期アップロードを試みます。

いくつかの発言:

  1. トリッキーなことは、アップロードしてローカルファイルを削除するコピーとアップロード、またはアップロードと削除の戦略を設定できることです。

  2. 2つ目の注意点は、アップロードされなくなるまで「ローカル」ストレージからファイルを提供することです。

  3. また、アップロードが失敗したときに何度も再試行するように構成することもできます。

インストールと使用法も非常にシンプルで簡単です。

pip install Django-queued-storage

INSTALLED_APPSに追加:

INSTALLED_APPS += ('queued_storage',)

models.py

from queued_storage.backends import QueuedStorage
queued_s3storage = QueuedStorage(
    'Django.core.files.storage.FileSystemStorage',
    'storages.backends.s3boto.S3BotoStorage', task='queued_storage.tasks.TransferAndDelete')

class MyModel(models.Model):
    my_file = models.FileField(upload_to='files', storage=queued_s3storage)
18
thedk

プロセスを切り離すことができます。

  • ユーザーはアップロードするファイルを選択してサーバーに送信します。この後、彼は「foofile.txtをアップロードしていただきありがとうございます。これでストレージバックエンドに保存されました」というページが表示されます。
  • ユーザーがファイルをアップロードすると、ファイルはサーバー上の一時ディレクトリに保存され、必要に応じて、一部のメタデータがデータベースに保存されます。
  • 次に、サーバーのバックグラウンドプロセスがファイルをS3にアップロードします。これは、サーバーへのフルアクセス権がある場合にのみ可能であるため、これに対して何らかの「デーモン」を作成できます(または単にcronジョブを使用できます)。*
  • 表示されるページは非同期でポーリングし、ユーザーに何らかのプログレスバーを表示します(または単純な「お待ちください」メッセージ。これは、ユーザーが「使用」(メッセージに入れる、またはそのようなもの)アップロード直後にそれ。

[*:共有ホスティングしかない場合は、ユーザーのブラウザで非表示のIframeを使用してスクリプトを開始し、ファイルをS3にアップロードするソリューションを構築できる可能性があります]

6
Martin Thurau

Webアプリケーションサーバーを使用せずに、メディアをs3サーバーに直接アップロードできます。

次の参考資料を参照してください。

Amazon APIリファレンス: http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?UsingHTTPPOST.html

A Django実装: https://github.com/sbc/Django-uploadify-s

3
digitalPBK

ここでの回答のいくつかはS3に直接アップロードすることを示唆しているので、ここにDjango pluploadを使用したS3ミックスイン: https://github.com/burgalon/plupload-s3mixin

0
Alon Burg

アップロードした画像で同じ問題が発生しました。 Celeryはタスクへの引数をピクルできる必要があるため、Celeryワーカーにファイルを渡すことはできません。私の解決策は、画像データを文字列に分解し、ファイルから他のすべての情報を取得して、このデータと情報をタスクに渡し、そこで画像を再構築することでした。その後、保存すると、ストレージバックエンド(S3など)に送信されます。画像をモデルに関連付ける場合は、インスタンスのIDをタスクに渡してそこで取得し、画像をインスタンスにバインドしてインスタンスを保存するだけです。

ファイルがフォームを介してアップロードされると、UploadedFileファイルのようなオブジェクトとしてビューで使用できます。 request.FILESから直接取得するか、最初にフォームにバインドしてis_validを実行し、form.cleaned_dataからファイルのようなオブジェクトを取得することをお勧めします。その時点で、少なくともあなたはそれがあなたが望む種類のファイルであることを知っています。その後、read()を使用してデータを取得し、他のメソッド/属性を使用して他の情報を取得できます。 https://docs.djangoproject.com/en/1.4/topics/http/file-uploads/ を参照してください

私は実際に、画像を非同期に保存するための小さなパッケージを作成して配布することになりました。ご覧ください https://github.com/gterzian/Django_async まさに画像用であり、フォークして状況に応じた機能を追加することができます。 https://github.com/duointeractive/Django-athumb とS3で使用しています

0
gterzian