djangoappengineでBlobstoreを用いてファイルアップロード・ダウンロードを実装する
djangoappengineでファイルアップロード、ダウンロードを実装するにはfiletransferを使うのが基本だと思いますが、このサンプル通りに実装すると、アップロード時の動きがGoogle App Engineに隠蔽されまくってて、謎の挙動がいっぱいあります。(単純に私のスキルに起因するものかと思いますが)
そこで、ちょっと工夫してみたいと思います。
モデルにフィールドを追加する
ファイルを保持させたいモデルにフィールド追加します。例えば、
class UserProfile(models.Model) profile_photo = models.FileField(upload_to='p', blank=True)
といったように。upload_toは適当で良いと思いますが、指定しておかないとどっかでエラーしたような気がします。
アップロードを実装
viewのファイルを編集します。アップロードされたファイルはrequest.FILES['profile_photo']といった形で取得できます。
このファイルを以下の関数でブロブストアに保存します。
(※2011/06/20現在、この方法はExperimental(実験的)とされています。使うかどうかは各個人の責任としてください)
from __future__ import with_statement #ファイルの先頭に記述する必要あり from google.appengine.api import files def _upload_to_blobstore(file): file_name = files.blobstore.create(mime_type='image/jpeg') with files.open(file_name, 'a') as f: for chunk in file.chunks(): f.write(chunk) files.finalize(file_name) return files.blobstore.get_blob_key(file_name)
戻り値でBlob Keyが返ってきます。これはダウンロードの際に必要になるので、データベースに保存します。
bk = _upload_to_blobstore(request.FILES['profile_photo']) # upがUserProfileのインスタンスだとすると up.profile_photo = str(bk)
up.profile_photoはFileFieldですが、内部的にはBlobKeyが文字列で保存されているだけなので、問題なく動作します。
ダウンロードを実装
ここもAppEngineのAPIを直接たたこうかと思いましたが、あまり上手くいかなかったので、filetransferを使います。
ダウンロードに関してはサンプル通りに実装すれば問題ありません。
def profile_photo_download_handler(request, user_pk): profile = get_object_or_404(UserProfile, user__pk=user_pk) if profile.profile_photo: return serve_file(request, profile.profile_photo) else: return HttpResponseRedirect('/static/images/default_profile_photo.png')
こんな感じで。
適当に解説してきましたが、不明な点、質問がありましたら、コメントしてください。答えられる範囲で答えます。