モデルを使う

SQLObject?はPythonオブジェクトを扱うようにデータベースにアクセスすることを可能にします。目に見える部分の裏側でSQLのクエリが実行されるのです。データベースに新しい行を挿入するためには適切なクラスからのオブジェクトを初期化するだけです。たとえばBookという モデル定義 があったとすると、デバッグログ( ?debug=1&debugOutput=1 )が有効になった状態で tg-admin shell を使うとこんなふうになります:

>>> Book(isbn="1234567890", title="A Fistful of Yen",
           description="An evocative look at Japanese currency "
                       "surrounded by hands.")
    1/QueryIns:  INSERT INTO book (isbn, description, title) 
                 VALUES ('1234567890',
                         'An evocative look at Japanese currency surrounded by
                          hands.', 'A Fistful of Yen')
    1/QueryIns-  >   1
    1/COMMIT  :  auto
    1/QueryOne:  SELECT isbn, title, description FROM book WHERE id = 1
    1/QueryR  :  SELECT isbn, title, description FROM book WHERE id = 1;
    1/QueryOne-  >   (u'1234567890', u'A Fistful of Yen',
                      'An evocative look at Japanese currency surrounded by
                       hands.')
    1/COMMIT  :  auto
   <Book 1 isbn='1234567890' title='A Fistful of Yen' 
    description="'An evocative loo...'">

キーのハンドリングには別の方法もありますが、SQLObjectはデフォルトでそれぞれのテーブルが整数のプライマリキーを持つようにセットアップされています。プライマリキーは id 属性を通して得ることができます。SQLObjectではIDによってデータを得るのが非常に簡単です。

>>> Book.get(1)
        <Book 1 isbn='1234567890' title='A Fistful of Yen'
                description="'An evocative loo...'"> 

isbn に対して行ったように、 alternateID カラムを指定すると、SQLObjectはその値によって検索できるように自動的にクラスメソッドを生成します:

>>> Book.byIsbn("1234567890")
    1/QueryOne:  SELECT id, isbn, title, description FROM book 
                 WHERE isbn = '1234567890'
    1/QueryR  :  SELECT id, isbn, title, description FROM book
                 WHERE isbn = '1234567890'
    1/QueryOne-  >   (1, u'1234567890', u'A Fistful of Yen', 
                        'An evocative look at Japanese currency surrounded by
                         hands.')
    1/COMMIT  :  auto
        <Book 1 isbn='1234567890' title='A Fistful of Yen'
         description="'An evocative loo...'">

もちろん単純なIDによる検索以上のことをする必要があるときがあるでしょう。SQLObjectはPythonのようにクラスを指定できるように select() というクラスを用意しています。またクラスはプレースホルダへアクセスするための特別な q という属性を持っています。例えば、isbnカラムにクエリを行うときには Book.q.isbn などとします。例えばこんなふうに:

>>> list(Book.select(AND(LIKE(Book.q.title, "%Fistful%"),
                              Book.q.isbn=="1234567890")))
    1/Select  :  SELECT book.id, book.isbn, book.title, book.description
                 FROM book
                 WHERE ((book.title LIKE '%Fistful%') AND
                        (book.isbn = '1234567890'))
    1/QueryR  :  SELECT book.id, book.isbn, book.title, book.description
                 FROM book 
                 WHERE ((book.title LIKE '%Fistful%') AND
                        (book.isbn = '1234567890'))
    1/COMMIT  :  auto
        [<Book 1 isbn='1234567890' title='A Fistful of Yen'
          description="'An evocative loo...'">]

上記の例で list() を呼び出していることに注意してください。selectクラスメソッドは SelectResults? オブジェクトを返します。SelectResultsがきれいなのは、そこからデータを引っ張ってくるまで、それは結果のプレースホルダとなってることです。結果をリストに変換するよりもむしろ、マッチする行の数だけを得るためにselect呼び出しの最後に .count() を追加しています。

アップデートは非常に簡単です: 属性を変えるだけです!属性を変えるとSQLObjectは UPDATE SQL を発行します。しかし時にはいくつかのカラムを変更したり、個々のアップデートをいちいち行いたくないと思うかもしれません。インスタンスはそれらをすべて一度にセットしてくれる set() メソッドを持っています。両方のスタイルを試してみましょう:

>>> book.title = "A Fistful of Foobar"
    1/Query   :  UPDATE book SET title = 'A Fistful of Foobar' WHERE id = 1
    1/QueryR  :  UPDATE book SET title = 'A Fistful of Foobar' WHERE id = 1
    1/COMMIT  :  auto
>>> book.set(title="A Fistful of Yen 2: Electric Boogaloo", isbn="37")
    1/Query   :  UPDATE book SET isbn = '37', 
                    title = 'A Fistful of Yen 2: Electric Boogaloo' WHERE id = 1
    1/QueryR  :  UPDATE book SET isbn = '37', 
                 title = 'A Fistful of Yen 2: Electric Boogaloo' WHERE id = 1
    1/COMMIT  :  auto

TurboGears?では "connection hub" を使ったトランザクションの利用が簡単です。コネクションハブは必要に応じてデータベースに接続し、トランザクションを始め、コミットし、ロールバックし、終えるメソッドを提供します。以下はトランザクションの例です:

>>> book.title
    'A Fistful of Yen 2: Electric Boogaloo'
>>> hub.begin()
>>> book.title = "A Fistful of Yen 3: The Sequel That Shouldn't Be"
    1/Query   :  UPDATE book SET 
                 title = 'A Fistful of Yen 3: The Sequel That Shouldn''t Be' 
                 WHERE id = 1
    1/QueryR  :  UPDATE book SET 
                 title = 'A Fistful of Yen 3: The Sequel That Shouldn''t Be' 
                 WHERE id = 1
>>> hub.rollback()
    1/ROLLBACK:  
>>> hub.end()
>>> book.title
    "A Fistful of Yen 3: The Sequel That Shouldn't Be"
>>> book.sync()
    1/QueryOne:  SELECT isbn, title, description FROM book WHERE id = 1
    1/QueryR  :  SELECT isbn, title, description FROM book WHERE id = 1
    1/QueryOne-  >   (u'37', u'A Fistful of Yen 2: Electric Boogaloo', 
      'An evocative look at Japanese currency surrounded by hands.')
    1/COMMIT  :  auto
>>> book.title
      'A Fistful of Yen 2: Electric Boogaloo'

先ほどの例と異なって、これらのクエリには COMMIT : auto が無いことに注意してください。トランザクションが有効なので自動コミットは自動的に無効になるのです。自動コミットの無効化は、コネクションURIに autoCommit=0 を追加しても可能です。

メモリにあるbookオブジェクトがロールバックで自動的にデータベースの状態に戻らないのでは意味がありません。 sync() を呼ぶことでデータベースの値が再読込されます。

"A Fistful of Yen 2"を使い切ったら destroySelf() メソッドを使うことでそれをデータベースから削除することができます。

Previous: モデルを定義する : Next: Kidテンプレートの簡単な説明