ブログをGoogle App Engineへ移行してみる18
2011/02/06 21:17:19
今回は記事で使う画像を管理するところを作ろうと思う。
本当はエラー処理、バリデーションをしっくりいく形、使いやすい形で実装したいのだが色々試行錯誤しても中々うまくいかず、四苦八苦している。実際にコードを書いてて痛感するのはやっぱりPythonという言語の基本的な技術的不足ですな。
ということで勉強の傍ら考え続けて何か降りてくるのを待ちながら別のものを実装していくことにします。
そこで今回は「画像」というわけです。
画像といえど基本は同じですのでカテゴリーと同様にさくっと作ってみます。特有のところは少し説明を加えることにしましょう。
/admin.py
作りながら気になった点は
・許可する画像拡張子を制限する場合はどうするか?
・複数の画像を許可した場合表出の時「Content-Type」をどう切り分けるべきなのか?
・画像サイズ(容量)を制限する方法は?
などですが、用意されているAPIの制限エラーにまかせるとして「try〜except」で制限にひっかれば処理をパスするという方法が一番シンプルというかそれぐらいしかできないような感じがしました。あえて例えば「JPG、PNG」に限るとかはあまり意味がないような気もするしね…
あとは表出の場合をどうするかぐらいなのですが、APIに変換メソッドがあるのでデータストア登録前に変換するか出した際に変換して表示するかで例えばJPEGに統一することも可能といえば可能です。ここがちょっと苦しいところですが、「execute_transforms」メソッドは何らかの処理(リサイズや回転など)を最低ひとつでもしないとエラーが出るため、0度回転「photo.rotate(0)」するを仕方なくいれることで回避してみました。もっといい方法があればいいのですが。
ということで勉強の傍ら考え続けて何か降りてくるのを待ちながら別のものを実装していくことにします。
そこで今回は「画像」というわけです。
画像といえど基本は同じですのでカテゴリーと同様にさくっと作ってみます。特有のところは少し説明を加えることにしましょう。
/admin.py
##### This view below is "Picture" #################
class PictureList(webapp.RequestHandler, View):
def get(self):
self.template_values['pictures'] = [item.to_hash() for item in get_pictures()]
self.render()
class PictureNew(webapp.RequestHandler, View):
def get(self):
self.render()
def post(self):
picture = Picture()
name = self.request.get("name")
picture.name = name if name else 'unknown'
photo, width, height = utils.convert_to_jpeg(self.request.get("photo"))
picture.photo = photo
picture.width = width
picture.height = height
picture.put()
self.redirect("/admin/picture/")
class PictureEdit(webapp.RequestHandler, View):
def get(self, key):
self.template_values['picture'] = get_picture(key).to_hash()
self.render()
def post(self, key):
picture = get_picture(key)
name = self.request.get("name")
picture.name = name if name else 'unknown'
if self.request.get("photo"):
photo, width, height = utils.convert_to_jpeg(self.request.get("photo"))
picture.photo = photo
picture.width = width
picture.height = height
picture.put()
self.redirect("/admin/picture/")
class PictureDelete(webapp.RequestHandler):
def get(self, key):
delete_items(key)
self.redirect("/admin/picture/")/main.pyclass PictureShow(webapp.RequestHandler):
def get(self, key):
picture = get_picture(key)
if picture and picture.photo:
self.response.headers['Content-Type'] = 'image/jpeg'
self.response.out.write(picture.photo)
return
self.error(404)/model.pydef get_picture(key):
try:
return db.get(key)
except:
return None
def get_pictures():
return Picture.all().order('-created_at')
~中略
class Picture(db.Model):
name = db.StringProperty()
photo = db.BlobProperty()
width = db.IntegerProperty()
height = db.IntegerProperty()
updated_at = db.DateTimeProperty(auto_now=True)
created_at = db.DateTimeProperty(auto_now_add=True)
def to_hash(self):
return {
'key': str(self.key()),
'name': self.name,
'photo': '/picture/show/'+ str(self.key()) if self.photo else '',
'width': self.width,
'height': self.height,
'updated_at': utils.to_jst(self.updated_at),
'created_at': utils.to_jst(self.created_at)
}/utils.pydef convert_to_jpeg(image_data):
try:
photo = images.Image(image_data)
width = photo.width
height = photo.height
photo.rotate(0)
photo = photo.execute_transforms(output_encoding=images.JPEG)
except:
photo = None
width = 0
height = 0
return [photo, width, height]/template_admin/PictureNew.py{% extends "base.html" %}
{% block script %}{% endblock %}
{% block script_onload %}{% endblock %}
{% block script_function %}{% endblock %}
{% block h1 %}新規登録{% endblock %}
{% block contents %}
<form action="/admin/picture/new" method="post" enctype="multipart/form-data">
■画像名
<input type="text" name="name" value="" size="40" />
■画像
<input type="file" name="photo" value="" />
<input type="submit" value="追加する" />
</form>
{% endblock %}/template_admin/PictureList.py{% extends "base.html" %}
{% block script %}{% endblock %}
{% block script_onload %}{% endblock %}
{% block script_function %}
<script type="text/javascript">
function deletecheck(){
if(window.confirm('本当に削除してもよろしいですか?\nデータは完全に削除されます。')){
return true;
}else{
return false;
}
}
</script>
{% endblock %}
{% block h1 %}登録一覧{% endblock %}
{% block contents %}
{% for picture in pictures %}
<h2>{{ picture.name|escape }}</h2>
<p>{{ picture.created_at|date:"Y年m月d日 H時i分" }}</p>
<p>[<a href="/admin/picture/edit/{{ picture.key }}">編集</a>][<a href="/admin/picture/delete/{{ picture.key }}" onclick="return deletecheck()">削除</a>]</p>
<hr />
{% endfor %}
{% endblock %}/template_admin/PictureEdit.py{% extends "base.html" %}
{% block script %}{% endblock %}
{% block script_onload %}{% endblock %}
{% block script_function %}{% endblock %}
{% block h1 %}編集{% endblock %}
{% block contents %}
<form action="/admin/picture/edit/{{ picture.key }}" method="post" enctype="multipart/form-data">
■画像名
<input type="text" name="name" value="{{ picture.name|escape }}" size="40" />
■画像
<input type="file" name="photo" value="" />
{% if picture.photo %}
<img src="{{ picture.photo }}" />
横:{{ picture.width }}pix、縦:{{ picture.height }}pix
{% endif %}
<input type="submit" value="変更する" />
</form>
{% endblock %}動きはソースを追ってもらう方が理解しやすいと思います。作りながら気になった点は
・許可する画像拡張子を制限する場合はどうするか?
・複数の画像を許可した場合表出の時「Content-Type」をどう切り分けるべきなのか?
・画像サイズ(容量)を制限する方法は?
などですが、用意されているAPIの制限エラーにまかせるとして「try〜except」で制限にひっかれば処理をパスするという方法が一番シンプルというかそれぐらいしかできないような感じがしました。あえて例えば「JPG、PNG」に限るとかはあまり意味がないような気もするしね…
あとは表出の場合をどうするかぐらいなのですが、APIに変換メソッドがあるのでデータストア登録前に変換するか出した際に変換して表示するかで例えばJPEGに統一することも可能といえば可能です。ここがちょっと苦しいところですが、「execute_transforms」メソッドは何らかの処理(リサイズや回転など)を最低ひとつでもしないとエラーが出るため、0度回転「photo.rotate(0)」するを仕方なくいれることで回避してみました。もっといい方法があればいいのですが。