ブログをGoogle App Engineへ移行してみる14
2011/01/19 21:15:58
冗長すぎるコードが気になってくる量になってきましたので、整理するとともに全体を見直してみます。
一見して目立つ冗長コードは、
[1]テンプレートでレンダリングするところ
[2]テンプレートから利用する日付をJSTに変換する「jst_created_at」メソッド
です。比較的手をつけやすいかなと思いますので、どんどん変更していきます。
まずは[1]ですが、
テンプレートを呼び出す時点で異なる情報はテンプレート名と渡す値なので、それのみを引数で渡すメソッドを作ります。
ここで考えなければならないのはどこにその関数を定義するかというところですが、効率やDRYを考えれば下記の二つが思いつきます。
・「BaseRequestHandler」というクラスを作りそこに定義し、全てのリクエストハンドラーはそのクラスを継承する
・「util.py」というユーティリティーを定義するファイルをつくりそのモジュールをインポートする
これも好みになりますが、全てのリクエストハンドラーに共通する処理が多い場合、継承元クラスを用意する方がいいでしょうし、スポットで使う関数が欲しい場合にはユーティリティー形式の方がいいでしょう。
ここでは後者を選択することにします。
新たにルートに「util.py」というファイルを作ります。
/utils.py
で、以下のように使います。
/main.py
他の同じような箇所も変更しておきます。
次に[2]ですが、モデルクラスごとに同じソースを並べるのはスマートではありませんね。これも[1]と同様、全てのモデルクラスの継承元を作るかユーティリティー形式でいくかという感じですが、かなり古いブログ記事のことを思い出しました。
・Google App Engineでアプリを高速化する3つのtips(2008/05/26)
これによるとテンプレート側からモデルのメソッドを呼び出すのは効率が悪いよという経験則とのこと。やはりテンプレートには便利で簡単なモデルインスタンスを渡す方法ではなく、きちんと全てのデータを揃えてディクショナリの形で渡すのが幸せになれるらしい。
では現状のモデルクラスのメソッドではなくユーティリティにメソッドを定義する方がいいのでしょう。またかなり前に考えて却下した日付の自動入力をせずにJSTに変換してからputするという方法をとった方が逆にすっきりするな〜とも思えてくる。
何故ならputするのは管理者一人であるのに対してselectは不特定多数、明らかにputで頑張る方が理にかなっている。
/utils.py
これをもってput時に「updated_at」と「created_at」に値を代入してやればよい。もちろんモデルクラスのコンストラクタを取り除いておくことを忘れないようにします。
う〜んダメですね…
きっちりした形のJST時間(例えば「2011-01-19 15:17:34.188000+09:00」)だと強制的にUTCに変換されるような仕様らしいです。
試しにきっちりした形でない9時間足しただけの形(例えば「2011-01-19 15:17:34.188000」)だと値が入ることは入るが、「tzinfo.py」でエラーが生じる…(多分UTCに変換しようとして正式な値ではないから変換できなくてそのままスルーされて値が入っているのだろう)
Googleのドキュメントを読むと「値はUTCで入れて出して使う時に任意のタイムゾーンに変換してねー」とある。
ぬぬぬ、もう一度戻してテンプレートに渡す値をJSTに変換する方式にする必要がありますな〜
あ、プロパティを「DateTimeProperty」ではなく「StringProperty」とかにして日付文字列にしたらどうなのかな〜とも思ったけど、それもスッキリした形ではないか…
/utils.py
[1]テンプレートでレンダリングするところ
[2]テンプレートから利用する日付をJSTに変換する「jst_created_at」メソッド
です。比較的手をつけやすいかなと思いますので、どんどん変更していきます。
まずは[1]ですが、
path = os.path.join(os.path.dirname(__file__), 'template/entries/index.html') self.response.out.write(template.render(path, template_values))毎回書くには長いですね。
テンプレートを呼び出す時点で異なる情報はテンプレート名と渡す値なので、それのみを引数で渡すメソッドを作ります。
ここで考えなければならないのはどこにその関数を定義するかというところですが、効率やDRYを考えれば下記の二つが思いつきます。
・「BaseRequestHandler」というクラスを作りそこに定義し、全てのリクエストハンドラーはそのクラスを継承する
・「util.py」というユーティリティーを定義するファイルをつくりそのモジュールをインポートする
これも好みになりますが、全てのリクエストハンドラーに共通する処理が多い場合、継承元クラスを用意する方がいいでしょうし、スポットで使う関数が欲しい場合にはユーティリティー形式の方がいいでしょう。
ここでは後者を選択することにします。
新たにルートに「util.py」というファイルを作ります。
/utils.py
import os
from google.appengine.ext.webapp import template
def render(self, template_name, template_values={}):
path = os.path.join(os.path.dirname(__file__), template_name)
self.response.out.write(template.render(path, template_values))
「render」という関数を定義。見たまんまですが、「テンプレート名」と「テンプレート値」を渡してやるだけです。「テンプレート値」はデフォルトでは空白の「{}」を定義します。で、以下のように使います。
/main.py
import util
class EntryList(webapp.RequestHandler):
def get(self):
entries = Entry.all().order('-created_at')
template_values = {
'entries': entries
}
utils.render(self, 'template_admin/entries/index.html', template_values)2行が1行になった程度で劇的にソース量が減ったというわけにはいきませんが、スッキリわかりやすい形になりました。他の同じような箇所も変更しておきます。
次に[2]ですが、モデルクラスごとに同じソースを並べるのはスマートではありませんね。これも[1]と同様、全てのモデルクラスの継承元を作るかユーティリティー形式でいくかという感じですが、かなり古いブログ記事のことを思い出しました。
・Google App Engineでアプリを高速化する3つのtips(2008/05/26)
これによるとテンプレート側からモデルのメソッドを呼び出すのは効率が悪いよという経験則とのこと。やはりテンプレートには便利で簡単なモデルインスタンスを渡す方法ではなく、きちんと全てのデータを揃えてディクショナリの形で渡すのが幸せになれるらしい。
では現状のモデルクラスのメソッドではなくユーティリティにメソッドを定義する方がいいのでしょう。またかなり前に考えて却下した日付の自動入力をせずにJSTに変換してからputするという方法をとった方が逆にすっきりするな〜とも思えてくる。
何故ならputするのは管理者一人であるのに対してselectは不特定多数、明らかにputで頑張る方が理にかなっている。
/utils.py
import os
import datetime
from google.appengine.ext.webapp import template
def render(self, template_name, template_values={}):
path = os.path.join(os.path.dirname(__file__), template_name)
self.response.out.write(template.render(path, template_values))
class JST(datetime.tzinfo):
def utcoffset(self,dt):
return datetime.timedelta(hours=9)
def dst(self,dt):
return datetime.timedelta(0)
def tzname(self,dt):
return "JST"
def jst_now():
return datetime.datetime.now(JST())「util.jst_now()」とすれば日本時間の現在時刻が取得できる。これをもってput時に「updated_at」と「created_at」に値を代入してやればよい。もちろんモデルクラスのコンストラクタを取り除いておくことを忘れないようにします。
う〜んダメですね…
きっちりした形のJST時間(例えば「2011-01-19 15:17:34.188000+09:00」)だと強制的にUTCに変換されるような仕様らしいです。
試しにきっちりした形でない9時間足しただけの形(例えば「2011-01-19 15:17:34.188000」)だと値が入ることは入るが、「tzinfo.py」でエラーが生じる…(多分UTCに変換しようとして正式な値ではないから変換できなくてそのままスルーされて値が入っているのだろう)
Googleのドキュメントを読むと「値はUTCで入れて出して使う時に任意のタイムゾーンに変換してねー」とある。
ぬぬぬ、もう一度戻してテンプレートに渡す値をJSTに変換する方式にする必要がありますな〜
あ、プロパティを「DateTimeProperty」ではなく「StringProperty」とかにして日付文字列にしたらどうなのかな〜とも思ったけど、それもスッキリした形ではないか…
/utils.py
import os
import datetime
from google.appengine.ext.webapp import template
def render(self, template_name, template_values={}):
path = os.path.join(os.path.dirname(__file__), template_name)
self.response.out.write(template.render(path, template_values))
def to_jst(dt=datetime.datetime.now()):
return dt + datetime.timedelta(hours=9)上記のように変更しました。「utils.to_jst()」で現日本時刻、引数に「datetimeオブジェクト」を渡せば9時間足した日本時間を返します。引数がなければ現時刻がデフォルトになるようにという感じ。