|
GAEO_Example02
自動生成されたコードを修正してブログらしくする自動生成されたコードでは、表示内容を含め、まともに使用できる状態ではないので、これを修正してもう少し使える状態に仕上げていきます。 注)ファイル名を示す場合は、全てプロジェクトルートからの相対パスで表記します。 デバッグのためにログを出力する本来はユニットテストを利用する方がよいとは思いますが、手っ取り早くアプリの状況をログに表示したい場合には、標準のログパッケージが便利です。 次のようにログ出力パッケージを指定します。 import logging 次のように使用します。 logging.info("some message")
logging.info("%s" % someValue)
logging.error("some error message")一覧表示はデータストアのキー値ではなく、タイトルと日付を表示する生成された状態では、データストアのID(キー)の値が表示されていますが、これでは内容を把握できないので、タイトルを表示するように変更します。 プロジェクトの生成した「templates」ディレクトリ下の「index.html」の次の部分を変更します。 変更前 {% for r in result %}
<li><a href="/example1/show/{{ r.key }}">{{ r.key }}</a></li>
{% endfor %}変更後 {% for r in result %}
<li><a href="/example1/show/{{ r.key }}">{{ r.title }}</a></li>
{% endfor %}上記の result という変数は、コントローラのindexメソッド中では self.result と宣言され、データストアから取得したオブジェクトが格納されています。 現在は英語で表示されていますが、日本語で表示したい場合は、それぞれのテンプレートファイルを編集します。 対象のファイル群は、./application/templates/example2/ 以下にあります。 簡単なバリデーションを実装するバリデーションの実装には標準パッケージに含まれているDjangoの djangoforms という便利なパッケージがあるのですが、GAEOでは使用ができないようです。(少なくとも作者はうまくいかなかった。情報をお持ちの方は是非、ご連絡ください) というわけで、今回はGAEOのみで簡単なバリデーションを行ってみる事ことにします。 before_putメソッドにバリデーション処理を追加するGAEO 0.3には before_put という、データストアにデータを格納する直前に呼ばれるコールバックメソッドがあります。 今回はこれを使用して、タイトルの文字列長が10文字を超えたらエラーとして扱うという簡単なバリデーションを行ってみます。 下の例では、 validates_size_of というRailsではおなじみのメソッド名を使って、タイトルフォームに入力された文字列長をチェックしています。 ./application/model/example1.py def before_put(self):
logging.info("### before_put")
result = True
result = self.validates_size_of()
if result == False:
return False
logging.info("### Result:%s" % result)
return result
def validates_size_of(self):
max_size = 10
size = len(self.title.encode("UTF-8")) # 日本語は3文字としてカウントされる
size = len(self.title) # 日本語は1文字としてカウントされる
logging.info("******* size:%d" % size)
if size <= max_size:
self.errors = {} # 成功なら空
return True
else:
self.errors.update({"title_too_long" : u"タイトルが長過ぎます"})
raise NameError ('Title lengs is too long')
return False
passbefore_put() が False を返すと、例外がスローされますので、コントローラこれを捕捉します。 ./application/controller/example1.py def create(self):
try:
r = Example1(
# Uncomment all required properties here.
title = self.params.get('title', None),
content = self.params.get('content', None),
# フォームで入力せず、自動登録なのでコメントアウト
# posted_at = self.params.get('posted_at', None),
keyword = self.params.get('keyword', None),
)
for prop in Example1.properties():
if prop in self.params:
setattr(r, prop, self.params.get(prop))
result = r.put()
logging.info("### datastore result is %s", result)
self.flash['notice'] = u"追加しました。"
self.redirect('/example1')
except Exception, e:
# 必須項目のフォームに値が無い場合、バリデーションがFalseを返したときに例外が発生する
logging.info("*** ERROR => %s" % e)
self.__set_attr()
self.msg = u"入力に誤りがあります"
self.render(template='new')
############################################
# private method
############################################
def __set_attr(self):
"""
バリデーションでエラーがあった場合に、フォームに値を再セットするために使用する
"""
self.title = self.params.get('title')
self.keyword = self.params.get('keyword')
self.content = self.params.get('content')
pass例外処理の中では、フォームに入力された内容をセットし、追加画面に移動する処理を行っています。 また、これらの処理はcreate()とupdate()で同じ処理を行うので、プライベートメソッドset_attr()としてまとめています。 追加画面への移動は、self.redirect()ではなく、 self.render() を使用している事に注意してください。 アトリビュートについてupdate処理のようにデータストアから取得した値を、フォームに使用しているパラメータにセットする処理は、GAEOがscaffoldで出力した次のようなコードでもかまいませんが、 ./application/controller/example1.py def update(self):
try:
r = Example1.get(self.params.get('id'))
for prop in Example1.properties():
if prop in self.params:
setattr(r, prop, self.params.get(prop))
r.put()
self.redirect('/example1/show/%s' % (r.key()))
except Exception, e:
.
.
.GAEO 0.3から使用可能になった、 self. update_attributes() メソッドを利用する事もできます。このメソッドを使用した場合、次のようなコードになります。 r.put() が無い点に注意してください。 self. update_attributes() は自動で r.put() を呼び出します。 ./application/controller/example1.py def update(self):
try:
r = Example1.get(self.params.get('id'))
r.update_attributes(title=self.params.get('title'),
content=self.params.get('content')
)
self.redirect('/example1/show/%s' % (r.key()))
except Exception, e:
.
.
.エラーメッセージを表示する入力ミスなどのエラーメッセージを表示したい場合は、 self.msg というインスタンス変数に 直接 エラーメッセージを代入し、正常に終了した場合のメッセージを表示したい場合には、 self.flash['notice'] にメッセージを代入します。 例外後のエラーメッセージを self.msg に直接代入している理由は、self.redirect()ではなく、self.render()を実行しているので、リダイレクト時と違い、 self.before_action() が呼び出されないためです。 なお、self.before_action() は0.3から利用可能です。self.flashは単なる辞書配列ですので、 notice の部分は error や warning などとすることができます。 ./application/controller/example1.py def create(self):
try:
.
.
.
self.flash['notice'] = u"追加しました。"
self.redirect('/example1')
except Exception, e:
# 必須項目のフォームに値が無い場合、バリデーションでFalseを返したときに例外が発生する
logging.info("*** ERROR => %s" % e)
self.__set_attr()
self.msg = u"入力に誤りがあります"
self.render(template='new')./application/controller/example1.py def before_action(self):
notice = self.flash.get('notice', '')
self.msg = notice
pass./application/templates/bash.html <div id="content_inner">
{% if msg %}
<div class="flash" style="color:#f00">
<div class="notice">
<p>{{ msg }}</p>
</div>
</div>
{% else %}
<!-- メッセージ無し -->
{% endif %}
</div>これで、ブログに必要な一通りの処理が実装できました。 次回は、GAEのデータストアへのアクセスはCPU資源を大量に消費しますので、それを回避するために、キャッシュサービスを使用してみます。 |