コントローラー
少し前に、
app.yaml
いくつかのURLを既に定義しました。アプリケーションをそれらに正しく「応答」させる方法を見つけ出す時です。 マッピングは次のようになります。
#$ Id:app.yaml 4 2010-01-25 12:14:48Z sigizmund $ アプリケーション:helloworld バージョン:1 ランタイム:python api_version:1 ハンドラー: -url:/(統計|ログイン) スクリプト:main.py ログイン:必須 -url :. * スクリプト:main.py
ご覧のとおり、3種類のURLが定義されています-
/stats
、
/login
および「その他」。 通常の3つすべては同じ
main.py
スクリプトで処理されますが、設定は異なります-
/stats
および
/login
はアクティブなユーザーセッションを必要としますが、その他の場合はこれは必要ありません。
main.py
スクリプトの内容を見てみましょう。
#!/ usr / bin / env python '' ' $ Id:main.py 4 2010-01-25 12:14:48Z sigizmund $ '' ' インポートコントローラー google.appengine.extからwebappをインポート google.appengine.ext.webapp import utilから google.appengine.apiインポートユーザーから def main(): application = webapp.WSGIApplication([( '/'、controller.DefaultRequestHandler)、 ( '/ stats'、controller.StatsRequestController)、 ( '/ login'、controller.LoginController)]、 debug = True) util.run_wsgi_app(アプリケーション) __name__ == '__main__'の場合: メイン()
かなり簡潔です。 つまり、非常に簡潔ですが、同時に非常に重要です。
controllers
のコンテンツをインポートし、リクエストURLと対応するハンドラーに一致する
webapp.WSGIApplication
インスタンスを作成する
webapp.WSGIApplication
です。 通常、これらのハンドラーは、実際のアプリケーションの動作を決定する実際のコードからサービスコードを分離するために、個別のパッケージに入れると便利です。 これらのハンドラーを順番に検討してください。
DefaultRequestHandler-デフォルトハンドラー
上記のコードからわかるように、このハンドラーは、アプリケーションの「メインページ」、つまり「/」に到達したすべてのリクエストに使用されます。 そのコードは次のとおりです。
クラスDefaultRequestHandler(webapp.RequestHandler): '' ' デフォルトのリクエストを処理-ユーザーがログインしているかどうかを確認します。 もしそうなら-に関する情報を保存します データベースへの彼の訪問。 '' ' def get(self): ユーザー= users.get_current_user() ページ=なし ユーザーでない場合: page = view.StartPage(self.request) その他: page = view.WelcomePage(self.request) page.render(self.response.out)
基本的に、このコードは、ページ自体のコンテンツを生成せず、いくつかの補助クラスを使用することを除いて、 最初の部分の
MainHandler
コードと
MainHandler
です。 この段階では、彼らが何をしているのかを考慮しません-私たちにとっては、彼らが私たちの要件を満たすHTMLを生成することを知るだけで十分です-つまり、これはログインしていないユーザーにログインを提供し、それに成功した人を歓迎します。
ログインハンドラー-2ページ間
アプリケーションの構造を示す画像を思い出させてください:
/login
ページの説明からわかるように、ユーザーは自動的にリダイレクトされ、ページ
/
も自動的にリダイレクトされます。 このページで何が起こっていますか? これを行うには、2つのクラスを一度に検討する必要があります。
クラスLoggedInRequestHandler(webapp.RequestHandler): def currentVisitor(自己): ユーザー= users.get_current_user() #/ loginおよび/ statsが指定するように、ユーザーをチェックするべきではありません #ログイン:app.yamlで必要 q = model.Visitor.all() q.filter(「ユーザー=」、ユーザー) qr = q.fetch(2) len(qr)== 0の場合: u = model.Visitor() elif len(qr)> 1: #ここで何かがひどく間違っている、それは起こるべきではない #しかし、それでもまだ logging.error(「データストアでユーザー%sを複製しています」%user.nickname()) 例外を発生させます(「データストアでuser%を複製しています」%user.nickname()) その他: u = qr [0] self.currentVisitor = u あなたを返す
これは最良のアーキテクチャソリューションではないかもしれませんが、説明のために、クラスを宣言し、
webapp.RequestHandler
から継承し
webapp.RequestHandler
。 ご覧のとおり、説明したクラスは
get
メソッドを定義していません。つまり、独立した開発者としては、ほとんど役に立たないでしょう。 彼がしているのは、データストアから取得するか、新しい
Visitor
インスタンスを作成して返す
currentVisitor()
メソッドを提供することだけです。 このコードをさらに詳しく検討してください。
説明したアプローチでは、このタイプの「すべて」のオブジェクトで始まるDatastore Queryを使用し、その後
filter()
および
ancestor()
呼び出して最終データセットを徐々に「洗練」します。 上記の例は非常に単純ですが、データストアから必要なレコードを抽出するために必要なほとんどすべてを示しています。 もちろん、実際のアプリケーションでは、このクエリはおそらくはるかに複雑になります。
このような便利なクラスができたので、ハンドラーを簡単に記述できます。
クラスLoginController(LoggedInRequestHandler): '' ' ログインイベントを処理するためだけにこのコントローラーを使用します '' ' def get(self): u = self.currentVisitor() u.hits = u.hits + 1 u.put() self.redirect( '/')
コードからわかるように、ハンドラーは現在のユーザーに関連付けられたVisitorインスタンスを受け取り(作成する可能性があります)、訪問数を1つ増やして、インスタンスを保存します。 その後、ユーザーは苦労せずにメインページにリダイレクトされます。 URL
/login
必須ログインが必要である
/login
マークされているため、ユーザーを確認する必要がなくなります(つまり、ユーザーが認証なしでログインしようとすると、ログインページに自動的にリダイレクトされます)。
StatsRequestController-リクエストに関する統計
最後のハンドラーのコードは非常に単純です。 それは非常に単純なので、明らかに何か他のものがあるはずであることを示唆しています:
クラスStatsRequestController(LoggedInRequestHandler): def get(self): u = self.currentVisitor() page = view.StatsPage(self.request、u) page.render(self.response.out)
確かに、何か他のものがあります。 これはプレゼンテーションと呼ばれるもので、Djangoテンプレートを使用します。記事の次の部分で説明します;-)
SVNで完全なソースコードを表示できることを思い出してください。質問やコメントをお待ちしています。
PS考えてください、Habrでバックライト付きのソースをアップロードする方法-そうでなければ、すべての写真をアップロードします!