TurboGearsのチュートリアルを日本語訳して実行してみる(その1)
Brian's TurboGears Tutorialを超訳*1ししてみる。
英語力は中学生もびっくりな感じなので、後学のために指摘していただける幸いです。
Brian's TurboGears Tutorial
Status: Contributed, Needs updating*2
コンテンツ
- TurboGearsのインストール
- プロジェクトの骨組みの作成
- モデルの構築
- コントローラの構築
- リソーステンプレートの適用
- 独自テンプレートの作成
- フォーム処理
- 非同期JavaScriptの追加
- 高度な機能
- ライセンス
TurboGearsプロジェクトを始めましたか?
このページにはTurboGearsを知るための必要な情報があります。
ここではユーザ認証のフレームワークや自動生成のForm機能、バリデートのような詳細な機能については述べません。代わりに、このチュートリアルでは、TurboGearsの基本的な振る舞いについて、深く理解することに焦点を当てます。
チュートリアルのアプリケーションはマルチユーザToDo リストマネージャです。筆者はこのプロダクトの最終版を自分のWEBサーバで運営しています。
TurboGearsのインストール
このチュートリアルはTurboGears1.0b1を対象(cover)としています。
Note:ファイル名は最新のバージョンでは違っているかもしれません。基本的にはバージョンがまたがっても動くでしょう。
もしsetuptoolsをインストールしているならば、次のようにします。
$ easy_install -Uf TurboGears
もしなければ、下の箇所(URL)で取得します。
http://www.turbogears.org/download/
適切な場所でtg-adminを実行します。*1
$ tg-admin
出力結果はこのようになります。
TurboGears 1.0b1 command line interface Usage: /usr/local/bin/tg-admin [command] [options] Available commands: ...
Note: パッケージのアルファ版やRC版がリリースされてます。setuptoolsはパッケージのよくないバージョンを取得する可能性があります。もっとも起きそうな結果は、いくつかのステップ中のImportErrorかAttributeErrorです。もし起こったなら、TurboGearsメーリングリストをチェックしてください。これらは、たいてい簡単に解決できます。http://groups.google.com/group/turbogears
*1:この場合TurboGearsのPATHが通っているHOMEディレクトリなどを指す。
プロジェクトの骨組みの作成
次のように入力してプロジェクトを作成します。
$ tg-admin quickstart
このチュートリアルではプロジェクトを'tutorial'と呼びます
Enter project name: tutorial Enter package name [tutorial]: ...
tg-admminによって作られたディレクトリに移動します。これから先、チュートリアルの間でのいくつかの参照パスは、このディレクトリの相対関係です。
$ cd tutorial/
この場所はプロジェクトのオペレーション場所です。これはビルトインのウェブサーバを利用するケースだと理解してください。
$ python start-tutorial.py
すべて動いたならば、ブラウザでhttp://localhost:8080にアクセスしてください。そしてwelcomeメッセージを確認してください。もし、うまくいかない場合、おそらくTurboGearsのインストールに失敗しています。
ビルトインのサーバのポート番号を変えるにはdev.cfgを編集します。
server.socket_port = 8080
To use the default 'production' configuration, specify which configuration file to use when starting the server:
WEBサーバの起動時に明確にコンフィグレーションファイルを利用するには以下のようにします。
$ python start-tutorial.py prod.cfg
モデルの構築
まず最初にTurbogearsが利用するデータベースカスタマイズをします。もし、データベースを利用しないならば次のセクションに行きます。
"dev.cfg"を開いてあなたが使うデータベースの適切なコメントラインの場所を探します。
このチュートリアルではSQLiteを利用します。理由はサーバコネクトの代わりにローカルファイルを利用するので操作が容易だからです。
sqlobject.dburi = "sqlite:///home/brian/tutorial/tutorial.sqlite"
Note SQLiteを利用する場合はURIは絶対パスである必要があります。もちろんSQLiteがインストールされている必要もあります。
"dev.cfg"を閉じます。チュートリアルの終わりまで、これを変更することはないです。
データベーステーブルを定義します。既にある tutorial/model.py のファイルを開きます。
TurboGearsはデータベースの抽出にSQLObjectを利用します。SQLObjectの中では、クラスはテーブルをあらわし、クラスのアトリビュートはテーブルの列をあらわします。
To-Doリスト アプリケーションを作成するわけですから、tutorial/model.pyに次のようなクラスを加えます。
class User(SQLObject): email = StringCol(alternateID=True) lists = MultipleJoin('List') class List(SQLObject): title = UnicodeCol(notNone=True) user = ForeignKey('User') items = MultipleJoin('Item') class Item(SQLObject): value = UnicodeCol(notNone=True) list = ForeignKey('List')
このモデル内では、ユーザはユニークなE-mailアドレスと複数のリストを持つことができる。リストは表題を持ち、一つのオーナーと複数のアイテムを持つ。アイテムは値とそれらを含むリストです。
テーブルの定義と利用のために、SQLObjectのドキュメンテーションを参照します。
http://sqlobject.org/SQLObject.html
dev.cfg内にTurboGearsがデータベースで使う新しいテーブル定義の情報があります。
テーブルの作成には次を実行します。
$ tg-admin sql create
エラーが出なければテーブル作成は成功です。
テーブル定義に変更が必要な場合、現在のデータベースのものを捨てます。そして、テーブルを再作成します。*1
$ tg-admin sql drop <--- DB削除 $ tg-admin sql create <---DB作成
テーブルを作り終えた後、プロジェクトにあるPython Shellでインタラクティブに行の追加をテストします。
Shellをスタートさせます。
$ tg-admin shell
トランザクション内でデータを追加か修正をします。コミットなしでシェルを抜けるとデータベースには保存されません。
トランザクションのコミットには、データを変更後、シェルで次のようにタイプします。
>>> hub.commit() インタラクティブなシェルを使ってテーブルをテストします。順序に従ってデータベースにいくつかのアイテムをinsertをします >>> u1 = User(email="exogen@gmail.com") >>> u1.email 'exogen@gmail.com' >>> u1.id 1 >>> u1.lists [] >>> l1 = List(title="Groceries", user=u1) >>> l1.title u'Groceries' >>> l1.user <User 1 email='exogen@gmail.com'> >>> l1.user.email 'exogen@gmail.com' >>> l1.items [] >>> u1.lists [<List 1 title=u'Groceries' userID=1>] >>> i1 = Item(list=l1, value="Milk") >>> i2 = Item(list=l1, value="Eggs") >>> i3 = Item(list=l1, value="Bread") >>> [item.value for item in l1.items] [u'Milk', u'Eggs', u'Bread'] >>> len(l1.items) 3 セーブするためにコミットすることを忘れないでください。 >>> hub.commit()
テーブルが十分に動いたなら、model.pyを閉じてください。
今後、チュートリアルの終わりまで変更する必要はないです。
コントローラーの構築
コントロラーは、リクエストがウェブサービスに来たときにコードを取得して実行する記述の方法です。
Python関数へリクエストURLとパラメータの一致して TurboGearsはCherryPyを呼び出して利用します。
tutorial/controllers.pyを開き、追記と修正を始めます。
contorollers.pyのRoot classを下のコードで置き換えたら、TurboGearsの"Hello, world!"相当のアプリケーションができます。
class Root(controllers.RootController): @turbogears.expose() def index(self): return "Hello, world!"
もう一度サーバをスタートさせて、ブラウザでhttp://localhost:8080へアクセスします。すると、テキストの中に"Hello, world!"が表示されます。
どうですか、動いていますか?
RootコントローラーはウェブサービスのルートURL(/)に相当します。/ のリクエストを受け取ったら、TurboGearsはRoot Controllerのiindex メソッドを見ます。indexメソッドはウェブディレクトリのindex.htmlに相当します。
publicリソース(expose)を作ります。exposeはturbogears.exposeに付随のディレクターです。*1
@turbogears.expose()
コード内のexposedメソッドはリソースを受け取った時に実行されます。Rootコントローラにはたくさんのresourceを追加することができます。
@turbogears.expose() def about(self): return "This tutorial was written by Brian Beck."
ブラウザでhttp://localhost:8080/about をアクセスしてください。
開発中はWEBサーバの再起動なしにコントローラーを作り替えることが可能です。
リクエストはパラメータも持っています。GETリクエストのURLやエンコード済みのフォームinput内のPOSTリクエストがあります。
両方のメソッドはどちらもコントローラでは同じ方法です。
@turbogears.expose() def about(self, author="Brian Beck"): return "This tutorial was written by %s." % author
/aboutのリクエストではのテキストメッセージが出てきます。しかし、レスポンス /about?autor=Napoleon の表示は次のようになります。
"This tutorial was written by Napoleon."
pathコンポーネントを加えます。
resourceを含んだクラスインスタンスをRootコントローラのアトリビュートに加えます。
ここに"users"pathコンポーネントをRootコントローラへ加えます
import model class Users: @turbogears.expose() def index(self): users = model.User.select() ※ import model が必要 return ", ".join(user.email for user in users) class Root(controllers.RootController): users = Users() ...
/users/indexか/usresにブラウズするとデータベースの中のusersリストが表示されます。
コントローラーの構造はCherryPyのドキュメントを参照します。
http://www.cherrypy.org/wiki/CherryPyBook
いくつかのuserは自分自身のリソースをUsersコントローラの中に持っています。
しかし、この要求はデータベース内のすべてのユーザのメソッドに加えることとなる。
幸運にも、これらはダイナミックpathコンポーネントで簡単に解決できる。リソース要求があったとき、対応したコントローラーが見つけることができない。呼び出されたdefaultメソッドはリクエストリソースの名前を引数(argument)として呼び出されます。
class Users: ... @turbogears.expose() def default(self, userID): try: userID = int(userID) except ValueError: return "Invalid user ID!" try: user = model.User.get(userID) except model.SQLObjectNotFound: return "No such user!" else: return user.email
ブラウザで/user/1にリクエストするとID 1のユーザのe-mailアドレスが表示されるか、IDが見つからなかった場合に"No such user!"と表示されます。/users/dogをリクエストすると通常tableのIDはIntegersなので"invalid user ID!"と表示されます。
とりあえず今日はここまで。
残りは次回に続く。。。のか???
*1:from turbogears import expose を記述してると@expose()だけでよい