Djangoで画像ファイルのアップロード


Pocket

Openshift環境での画像アップロード方法です。

基本的には、下記に書いてある通りですが、ハマったところのメモなども交えて。
http://django-docs-ja.readthedocs.org/en/latest/ref/forms/api.html#binding-uploaded-files

<環境>
django 1.4
python 2.7

 

アップロード処理

まずは画像のアップロードフォームの作り方です。
手順は、
1.モデルの作成
2.フォームの作成
です。

 

1.モデルの作成

・models.py

from django.db import models
class ImageFile(models.Model):
  owner = models.CharField(max_length=20)
  data = models.ImageField(upload_to='images')

所有者名と画像を保存するようにしてみました。
ImageField.upload_toはアップロード先のパスで、settings.pyで設定したMEDIA_ROOT以下のパスを指定します。
上記の例だとMEDIA_ROOT/images/に保存されていくようです。

あと、ImageFieldを使用する場合は、Python Imageging Library(PIL)が必要になるので、インストールしましょう。

 

2.フォームの作成

・views.py

from django.shortcuts import render_to_response
from django.template import RequestContext
from openshift.app.models import ImageFile
from django import forms

def upload_form(request):
  if request.method == "POST":
    form = UploadForm(request.POST, request.FILES)
    if form.is_valid():
      data = ImageFile()
      data.owner = from.cleaned_data['owner']
      data.image = request.FILES['imaage']
      data.save()
  else:
    form = UploadForm()  
  
  return render_to_response('home/upload.html', {'form':form}, context_instance=RequestContext(request))

class UploadForm(forms.Form):
  owner = forms.CharField(max_length=20)
  image = forms.FieleField()

・(テンプレート)upload.html

...省略
<form enctype="multipart/form-data" action="/upload/" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" = values="submit" />
</form>
...

これで、upload_formにアクセスした時には空のフォームを、入力がPOSTされた時には入力データを検証して保存をするところまで完成です。
後、上記例ではエラーハンドリングとか全くやってませんが、実際は必要ですね。

 
フォームオブジェクトを使用すると入力データの検証がis_valid()で簡単にできたり、フォームのHTMLを自動で吐いてくれるので便利です。
ついでに、この例のようにフォームの入力とモデルの内容が一致している場合は、「モデルからフォームを生成する」こともできるようです。

 

アップロードされた画像を表示する

次にアップロードされた画像を表示する方法です。
手順は下記の通り。
1.モデルオブジェクトの読み出してHTMLを作成
2.画像ファイルを公開するためのサーバー設定

 

1.HTMLの作成

・view.py

import os
from django.template import RequestContext
from django.shortcuts import render_to_response
from openshift.app.models import ImageFile

def view(request):
  items = []
  for item in ImageFile.objects.all():
    items.append({'owner':item.owner, 'image':item.image})
  return render_to_response('home/view.html', {'items':items}, context_instance=RequestContext(request))

・(テンプレート)view.html

...省略
{% for item : items %}
<img src="{{ item.image.url }}" alt="{{ item.image.name }}" />
{% endfor %}
...

・urls.py

...省略
from django.conf import settings
form django.conf.urls.static import static

urlpatterns = patterns(''
  ...省略
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

最初はurls.pyの変更が必要なことに気が付かないで、画像が取得できなくてハマりました。
「他のディレクトリを公開する」に書いてありますね。

ちなみにsettingsは、
MEDIA_ROOT = os.environ.get(“OPENSHIFT_DATA_DIR’, ”)
MEDIA_URL = ‘/media/’
こんな感じにしました。

 

2.サーバーの設定

ローカル開発環境だと、ここまでで画像表示ができていると思いますが、Openshiftサーバーだと表示できません。サーバー側の設定が必要です。

・$OPENSHIFT_REPO_DIR/wsgi/に.htaccessファイルを作成

RewriteEngine On
RewriteRule ^application/media/(.+)$ /static/media/$1 [L]

 
・シンボリックリンクの作成

ln -sf $OPENSHIFT_DATA_DIR/media $OPENSHIFT_REPO_DIR/wsgi/static/media

Apatchのリダイレクト機能を使って、http://~/media/*へのアクセスを、静的ファイル用のフォルダへリダイレクトして、さらにそこから実際の画像データが保存されたフォルダ($OPENSHIFT_DATA_DIR)へシンボリックリンクを使って参照すしています。

ちなみにシンボリックリンクはデプロイ毎に削除されてしまうので、下記参照のように、シンボリックリンクをデプロイ時に自動生成するスクリプトの書くといい感じです。

<参考>
http://masci.wordpress.com/2012/07/17/serving-django-media-files-in-openshift/

 
 

あとがき

ファイルのアップロードの基本的なことはできるようになりました。
またほんのちょっとですがDjangoに詳しくなったかな。

・・・にしても、Djangoの日本語記事ってあんまり見ないですね。
やっぱり人気ないんですかね。
(どっかでパフォーマンスが悪いとか書いてあるの見たけどそのせい?)
PHP関連のフレームワークとかRuby on Railsとかいっぱいあるのに。

python自体の人気がないってのもあるんだろうけど。
でも、“プログラミング言語別”の求人年俸額の順位、1位は「Python」で平均382万円”ですよ。

・・・トップが380万ってのも業界として悲しいものがあるけど、そんな中で1位ですよ。

はぁ、もうちょっと人気でてもいいんじゃないかと思います。
ではでは~。

 
 

Leave a Comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です