HOME > ブログ > ブログをGoogle App Engineへ移行してみる18

ブログをGoogle App Engineへ移行してみる18

今回は記事で使う画像を管理するところを作ろうと思う。






本当はエラー処理、バリデーションをしっくりいく形、使いやすい形で実装したいのだが色々試行錯誤しても中々うまくいかず、四苦八苦している。実際にコードを書いてて痛感するのはやっぱりPythonという言語の基本的な技術的不足ですな。

ということで勉強の傍ら考え続けて何か降りてくるのを待ちながら別のものを実装していくことにします。

そこで今回は「画像」というわけです。
画像といえど基本は同じですのでカテゴリーと同様にさくっと作ってみます。特有のところは少し説明を加えることにしましょう。


/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.py
class 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.py
def 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.py
def 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)」するを仕方なくいれることで回避してみました。もっといい方法があればいいのですが。


| Google App Engine | Comment:3 |
コメント
payday loan UK
payday loan UK
fhewinvc <a href="http://payday24loans.co.uk/ ">payday loan UK</a> yqngr <a href="http://paydayloanscheckrates.com/ ">Payday loans</a> fwNUV <a href="http://payday24loans.com/ ">bad credit payday loan</a> 1990
| | 2012/01/30 08:50:07
cialis kaufen
cialis kaufen
hikaqo <a href="http://qcialis.eu/ ">cialis kaufen</a> >:]] <a href="http://qcialis.it/ ">cialis online</a> zgNMv <a href="http://qviagra.fr/ ">viagra</a> >:-OOO <a href="http://qviagra.eu/ ">viagra online</a> RvefG <a href="http://qcialis.fr/ ">acheter cialis</a> 6171 <a href="http://qviagra.it/ ">viagra</a> UKOguu
| | 2012/02/04 13:03:12
Payday Loans UK
Payday Loans UK
gpgtmxym <a href="http://onlineukpaydayloans.co.uk/ ">Payday Loans UK</a> 2964 <a href="http://fastuspaydayloans.com/ ">payday loans</a> 6724 <a href="http://fastpaydayloanscanada.ca/ ">Payday Loan</a> %-[[[ <a href="http://fastpaydayloansus.com/ ">instant payday loans</a> >:-[
| | 2012/02/21 04:46:09
コメント投稿












画像リロード
*半角の小英字、数字で構成されています