フォーム処理

次の変更は、インタラクティブシェルの代わりにアプリケーション内でユーザとリストを管理するフォームです。

最初に、ユーザ削除と追加を加えます。両方の動作はユーザのユニークなe-mailアドレスを必要とするでしょう。
実行の動作はステータスメッセージをディスプレイへ表示させ、/users/indexへリダイレクトさせます。

これらのメソッドはPOSTリクエストの結果からです。そしてクライアントを直ぐにリダイレクトします。
新しいテンプレートは必要ないです。ここでは新しい2つのメソッドをUsersコントローラに追加します。

class Users:
    ...

    @turbogears.expose()
    def add(self, email):
        # Remove extra spaces
        email = email.strip()
        # Remove null bytes (they can seriously screw up the database)
        email = email.replace('\x00', '')
        if email:
            try:
                user = model.User.byEmail(email)
            except model.SQLObjectNotFound:
                user = model.User(email=email)
                turbogears.flash("User %s added!" % email)
            else:
                turbogears.flash("User %s already exists!" % email)
        else:
            turbogears.flash("E-mail must be non-empty!")
        raise cherrypy.HTTPRedirect('index')

    @turbogears.expose()
    def remove(self, email):
        try:
            user = model.User.byEmail(email)
        except model.SQLObjectNotFound:
            turbogears.flash("The user %s does not exist. (Did someone else remove it?)" % email)
        else:
            for l in user.lists:
                for item in l.items:
                    item.destroySelf()
                l.destroySelf()
            user.destroySelf()
            turbogears.flash("User %s removed!" % email)
        raise cherrypy.HTTPRedirect('index')

メソッドを追加のための注意。ここでは入力されたemailが空ではなく正しく作られたかを非常に簡単に検証した。
現実では、ここには正規表現を使う。ユーザの重複登録や存在しないユーザの変更の安全のために、すべてtry/exceptブロックします。
いくつか検証は一般のWebサービスには必要です。

ここで、フォームに複数のメソッドを加えます。actionはUsersコントローラに加えた対応するメソッドの名前です。
tutorial/templates/users.kidののhtmlの最後にこれを加えます

<form action="add" method="POST">
    <fieldset>
        <legend>Add a User</legend>
        <label for="email">Email:</label>
        <input type="text" name="email"/>
        <input type="submit" value="Add"/>
    </fieldset>
</form>

次に、リストユーザの削除ボタンを加えます。リストアイテムにボタンを加えるために、users.kidの中のリストを変更します。

<ol>
    <li py:for="user in users">
        <form style="float: right" action="remove" method="POST">
            <input type="hidden" name="email" value="${user.email}"/>
            <input type="submit" value="Remove"/>
        </form>
        <span>${user.email} (<a href="${user.id}">View lists</a>)</span>
    </li>
</ol>


Usersページを再読込して、ユーザの追加と削除を試します。turbogears.flashで呼ばれたステータスメッセージが結果として表示されます。

この処理はフォームへのリストとアイテムの修正に似ている。したがって、多くの説明しません。代わりに次のコードを見ください。

これは新しいtutorial/templates/user.kidのです。

<h2>${user.email}'s Lists</h2>
<div py:for="userList in user.lists">
    <form style="float: right" action="/removeList" method="POST">
        <input type="hidden" name="userID" value="${user.id}"/>
        <input type="hidden" name="listID" value="${userList.id}"/>
        <input type="submit" value="Delete This List"/>
    </form>
    <h3>${userList.title} </h3>
    <ol>
        <li py:for="item in userList.items">
            <form style="float: right" action="/removeItem" method="POST">
                <input type="hidden" name="userID" value="${user.id}"/>
                <input type="hidden" name="itemID" value="${item.id}"/>
                <input type="submit" value="Remove"/>
            </form>
            <span>${item.value}</span>
        </li>
    </ol>
    <form action="/addItem" method="POST">
        <input type="hidden" name="userID" value="${user.id}"/>
        <input type="hidden" id="listID" name="listID" value="${userList.id}"/>
        <label>Add Item: <input type="text" name="value"/></label>
        <input type="submit" value="Add"/>
    </form>
</div>
<form action="/addList" method="POST">
    <fieldset>
        <legend>Create a List</legend>
        <input type="hidden" name="userID" value="${user.id}"/>
        <label for="title">Title:</label>
        <input type="text" id="title" name="title"/>
        <input type="submit" value="Create"/>
    </fieldset>
</form>
個人的メモ7

from turbogears import controllers, expose, flashとしてやると、turbogearsをいれなくてもそれぞれ呼び出せる。
from model import * で modelがなくなる

ルートコントローラーを加えます。

class Root(controllers.RootController):
    ...

    @turbogears.expose()
    def addList(self, userID, title):
        try:
            userID = int(userID)
            user = model.User.get(userID)
        except (ValueError, model.SQLObjectNotFound):
            raise cherrypy.NotFound
        else:
            # Remove extra spaces
            title = title.strip()
            # Remove null bytes (they can seriously screw up the database)
            title = title.replace('\x00', '')
            if title:
                l = model.List(title=title, user=user)
                turbogears.flash("List created!")
            else:
                turbogears.flash("Title must be non-empty!")
        raise cherrypy.HTTPRedirect('/users/%s' % userID)

    @turbogears.expose()
    def removeList(self, userID, listID):
        try:
            listID = int(listID)
            l = model.List.get(listID)
        except ValueError:
            turbogears.flash("Invalid list!")
        except model.SQLObjectNotFound:
            turbogears.flash("List not found! (Did someone else remove it?)")
        else:
            for item in l.items:
                item.destroySelf()
            l.destroySelf()
            turbogears.flash("List deleted!")
        raise cherrypy.HTTPRedirect('/users/%s' % userID)

    @turbogears.expose()
    def addItem(self, userID, listID, value):
        try:
            listID = int(listID)
            l = model.List.get(listID)
        except ValueError:
            turbogears.flash("Invalid list!")
        except model.SQLObjectNotFound:
            turbogears.flash("List not found! (Did someone else remove it?)")
        else:
            # Remove extra spaces
            value = value.strip()
            # Remove null bytes (they can seriously screw up the database)
            value = value.replace('\x00', '')
            if value:
                item = model.Item(listID=listID, value=value)
                turbogears.flash("Item added!")
            else:
                turbogears.flash("Item must be non-empty!")
        raise cherrypy.HTTPRedirect('/users/%s' % userID)

    @turbogears.expose()
    def removeItem(self, userID, itemID):
        try:
            itemID = int(itemID)
            item = model.Item.get(itemID)
        except ValueError:
            turbogears.flash("Invalid item!")
        except model.SQLObjectNotFound:
            turbogears.flash("No such item! (Did someone else remove it?)")
        else:
            item.destroySelf()
            turbogears.flash("Item removed!")
        raise cherrypy.HTTPRedirect('/users/%s' % userID)
個人的メモ8

行頭にimport cherrypy が必要だった。

これは機能中に大きな変更を与えます。しかし、このページスタイルは悪くない。
今は、マークアップを見て、/tutorial/staitc/css/style.cssの中にどのように多くのスタイルを適応させるかを決める時間です。