SQLAlchemyを試す

デフォルトで、TurboGears 1.0ではORMとしてSQLObjectが、テンプレートシステムとしてKidが採用されており、TurboGears 2.0ではORMとしてSQLAlchemyが、テンプレートシステムとしてGenshiが採用される予定です。

SQLObjectとSQLAlchemyにしろ、KidとGenshiにしろ、どちらを使うか・どちらを学習すべきかという議論は後を絶ちませんが、まずはこう理解することが大切なのではないかと思います。

  • どちらを選択するのかはケースバイケースなので、一概に、そして明確に、「こちらがよい」とは誰も断言できない
  • 重要なのは両者の違いを把握し、自分のスキルや作成するアプリケーションの要件を鑑みながら適切な選択をすること

とはいえ、私のような知識も経験も目的もないようなダメダメ人間には、そもそも違いがよくわからないので大変です。ということで違いを知るという名目でいつものごとく新しいものに飛びついてしまうのです。

ちなみにSQLObjectとKidはTurboGears 2.0でデフォルトではなくなりますが、デフォルトでなくなるというだけでサポートはされます。「TurboGears 2.0は1.0と99%互換になる予定である」、という記述をTurboGearsのMLのどこかで読んだ記憶があります(残りの1%はCherryPy 2→CherryPy 3の問題)。

ActiveRecordとDataMapper

TurboGearsのドキュメントの中にSQLObjectVSSQLAlchemyというものがあります。これによると

The design of SO follows the Active Record pattern, while SA uses the Data Mapper pattern. This makes SA more flexible, but requires more code for simple operations.

ということらしいです。

SQLObjectはActiveRecordで、SQLAlchemyはDataMapperらしいです。ActiveRecord?DataMapper?なんじゃそれ、という感じですが、「OTN Japan - 今だからデータ・アクセスを真剣に考える! 第2回:データアクセスことはじめ(後編)」を見てみると概念化しやすい感じです。

SQLObjectやSQLAlchemyはPythonとデータベースの仲介役となってくれますが、仲介役として何をどのようにしてくれるのかがいろいろと違うようです。

SQLObjectはActiveRecord

SQLObjectを使う場合には自動的に、Modelに定義するPythonクラスがデータベースのテーブルに、Pythonメソッドがデータベースのカラムに対応するため、扱い方が直感的にわかりやすく、自分で決めなければならないこと(設定)も少なくてすみます。

Pythonとデータベースの対応があらかじめ決まっているなどの制約がある反面、わかりやすく設定も少ないというわけですか。しかし既存の決めごとというのは制約とはいっても初心者にはわかりやすくていいですよね。

SQLAlchemyはDataMapper

一方SQLAlchemyを使う場合には、SQLObject(ActiveRecord)のようなPythonとデータベースの対応が決まっていません。自分で何から何までコントロールできるためSQLObjectを利用する場合に比べてやりたいことが実現できるという利点があります。より高度なデータベース操作を行うことができるといってよいのではないでしょうか。

しかし何でもかんでもできてしまう反面、それに対する決めごと(設定)を記述する必要があるわけで、初心者には敷居が高いということになるでしょう。

すなわち

This makes SA more flexible, but requires more code for simple operations. In practice, the Active Record pattern is more appropriate for most web applications.

ということを忘れるべきではないと思います。

SQLAlchemyを試す

わかっちゃいるけどやめられない、というのは病気です。そうです。私は病気なのです。だからSQLAlchemyを試してしまうのです。以下は病気で頭がおかしくなってしまった人の書いたでたらめな文章なので信用してはいけません。

「-s」オプションを使ってSQLAlchemyを利用したプロジェクトを作成する

tg-adminのquickstartでは「-s」オプションを指定するとSQLObjectの代わりにSQLAlchemyを使うようになっています。これにプラスしてリレーションも確認したいのでidentityを使うために「-i」オプションも付けてしまいましょう。

ということでおもむろに

tg-admin quickstart tgbbs -s -i

としてtgbbsという試しのプロジェクトのひな形を作成することにします。しかし今回のミッションはSQLAlchemyを試すということなので、bbsとして完成させる気はさらさらありません。うひ。

ちなみにうちのTurboGearsはPython 2.5なので少しイレギュラーな動きをするかもしれません。「-s -i」以外のオプションは指定していませんので、データベースはsqliteですし、テンプレートはKidです。

identityのモデルはどうなってるのか

肝はもちろんモデルの設定です。とりあえずidentityのモデルがどうなっているのかを見ながらSQLAlchemyの使い方を調べてみることにします。

上記のquickstartで生成されたプロジェクトのmodel.pyを見てみると、すでにidentityのためのモデルが設定されています。ざっと適当に眺めているとだいたい3つの部分から構成されていることがわかります。

まずはテーブルの設定。

以下のような感じでデータベースのテーブルスキーマを設定しているようです。

visits_table = Table('visit', metadata,
    Column('visit_key', String(40), primary_key=True),
    Column('created', DateTime, nullable=False, default=datetime.now),
    Column('expiry', DateTime)
)

最初にメタデータとしてテーブル名を指定、その後各カラムの名前やデータ型などを指定しています。

次にクラスの定義。

以下のような感じでPythonオブジェクトを定義しているようです。利用するメソッドを定義すればOKということでしょうか。

class Visit(object):
    """
    A visit to your site
    """
    def lookup_visit(cls, visit_key):
        return Visit.get(visit_key)
    lookup_visit = classmethod(lookup_visit)

そしてマッパーの設定。

コンテクスト上で利用するPythonオブジェクトとテーブルの対応付けをしているっぽいです。

assign_mapper(session.context, Visit, visits_table)

assign_mapperのドキュメントも見ておくとよいかもぉ。

ちなみにassign_mapperはmapperの拡張なのですが、これらの違いについてはlingrにてaodagさんが解説してくれました

試しに簡単なモデルを作ってみる

リレーションを試してみたいのですが、とりあえず単純なところからいじるほうが安全だということを言い訳にして後回しにします(identity使った意味が…)。

ということで、bbsですから何らかのコメントが投稿されるわけですので超単純なコメントのモデルを作ってみます。

コメントには、idと、タイトルと、本文と、投稿日を設定しましょう。

comments_table = Table('comment', metadata,
    Column('comment_id', Integer, primary_key=True),
    Column('comment_title', Unicode(255)),
    Column('comment_body', Unicode(1024)),
    Column('posted', DateTime, nullable=False, default=datetime.now),
)

ちなみに投稿日のカラムは前述のvists_tableの定義から頂戴いたしました。

次にクラスの定義です。まぁ適当にほげほげと。

class Comment(object):
    def __init__(self, comment_title, comment_body):
        self.comment_title, self.comment_body = comment_title, comment_body

最後にテーブルとPythonクラスをマッピングします。

assign_mapper(session.context, Comment, comments_table)

データを投入してみる

まずはテーブルを生成するために、コマンドプロンプトからtgbbsのディレクトリへ入って

tg-admin sql create

します。

ちなみにdev.cfgにて

sqlalchemy.echo = 1 # デフォルトは0

としてやれば、sqlalchemyのログを出力させることができます。

データを投入するためにshellを起動します。コマンドプロンプトから

tg-admin shell

します。シェルに入ったら、コメントのインスタンスを作成し、データベースに保存します。

c = Comment('Test Comment', 'This is a test.')
c.flush()

うちではIPythonを使って、さらにsqlalchemy.echo = 1しているので以下のような感じになります。

C:\Documents and Settings\nyusuke\My Documents\TurboGears\tgbbs>tg-admin shell
Python 2.5 (r25:51908, Sep 19 2006, 09:52:17) [MSC v.1310 32 bit (Intel)]
Type "copyright", "credits" or "license" for more information.

IPython 0.7.3 -- An enhanced Interactive Python.
?       -> Introduction to IPython's features.
%magic  -> Information about IPython's 'magic' % functions.
help    -> Python's own help system.
object? -> Details about 'object'. ?object also works, ?? prints more.

In [1]: c = Comment('Test Comment', 'This is a test.')

In [2]: c.flush()
2007-04-05 01:15:50,467 INFO sqlalchemy.engine.base.Engine.0x..90 BEGIN
2007-04-05 01:15:50,467 sqlalchemy.engine.base.Engine.0x..90 INFO BEGIN
2007-04-05 01:15:50,467 INFO sqlalchemy.engine.base.Engine.0x..90 INSERT INTO co
mment (comment_title, comment_body, comment_posted) VALUES (?, ?, ?)
2007-04-05 01:15:50,467 sqlalchemy.engine.base.Engine.0x..90 INFO INSERT INTO co
mment (comment_title, comment_body, comment_posted) VALUES (?, ?, ?)
2007-04-05 01:15:50,467 INFO sqlalchemy.engine.base.Engine.0x..90 ['Test Comment
', 'This is a test.', '2007-04-05 01:15:50.468000']
2007-04-05 01:15:50,467 sqlalchemy.engine.base.Engine.0x..90 INFO ['Test Comment
', 'This is a test.', '2007-04-05 01:15:50.468000']
2007-04-05 01:15:50,467 INFO sqlalchemy.engine.base.Engine.0x..90 COMMIT
2007-04-05 01:15:50,467 sqlalchemy.engine.base.Engine.0x..90 INFO COMMIT

In [3]:

ここでデータベースの中身を調べるために一度shellを抜けて、コマンドプロンプトから

sqlite3 devdata.sqlite

します。

C:\Documents and Settings\nyusuke\My Documents\TurboGears\tgbbs>sqlite3 devdata.sqlite
SQLite version 3.3.10
Enter ".help" for instructions
sqlite> select * from comment;
1|Test Comment|This is a test.|2007-04-05 01:15:50.468000
sqlite>

わーい、保存されてるみたいですね。

眠たいので寝ます。おやすみなさ~ぃ。

カテゴリ
Turbogears Turbogears
トラックバック用URL:
http://nagosui.org:8080/Nagosui/COREBlog2/trying-sqlalchemy/tbping
コメントを追加

下のフォームに記入してコメントを追加できます。平文テキスト形式。

(必須)
(必須)
(必須)
(Required)
Enter the word

このBlogについて
Plone, Zope, Pythonなどのトピックについてのメモです。
カテゴリ
Plone (99)
Plone Products (23)
COREBlog2 (31)
COREBlog1 (29)
ReadingCOREBlog (7)
Zope (66)
Turbogears (18)
Django (12)
Python (26)
Linux (32)
Nagosui (13)
Design (34)
Misc (49)
moblog (5)
最近のエントリ
Plone3.2+その他もろもろのレシピ nyusuke 2009年01月07日
さらばファッキンKDDI nyusuke 2008年12月10日
Xoopsのテーマをいじる1 nyusuke 2008年12月08日
第13回名古屋大学吹奏楽団定期演奏会 nyusuke 2008年12月07日
最近のコメント
Re:WebデザイナーのためのDjangoはじめの一歩 nyusuke 2007年06月01日
Re:WebデザイナーのためのDjangoはじめの一歩 pateo 2007年05月31日
Re:東海Python Workshop 01終了 nyusuke 2007年05月31日
Re:東海Python Workshop 01終了 kfuruhata 2007年05月30日
Geek Test
I am 30% Geek.
Geek? Yes, but at least I got social skills.
You probably work in computers, or a history deptartment at a college. You never really fit in with the "normal" crowd. But you have friends, and this is a good thing.