Tag/SQLAlchemy

SQLAlchemyで遊んでみる。その2

SQLAlchemyで遊んでみる。その1 の続き。

今回は SELECT のやり方をちょくちょく試してみたよ。 まぁ、前回同様ドキュメントに従ったり従わなかったりはその場の気分でやっております。

テーブル定義とかは前回のものをそのまま使った。 ので、とりあえずはインポートする。 ただ、データは新しく作り直す事にした。

>>> import sha
>>> from tutorials import *

>>> # 一度テーブルを全部ドロップする。
>>> meta.drop_all(checkfirst=True)

>>> # テーブル作成。
>>> meta.create_all(checkfirst=True)

Session オブジェクトを作って、新しくデータを登録していく。

>>> # Sessionクラスを作る。
>>> Session = sessionmaker(autoflush=True, transactional=True)

>>> # Sessionクラスのインスタンス化。
>>> sess = Session()

>>> # とりあえず10個テストデータを作る。
>>> for i in range(10):
...    a = 'test%s' % (i + 1)
...    sess.save(User(a, sha.new(a).hexdigest()))

>>> # ココでコミット。
>>> sess.commit()

何も考えず全部取り出すならこんな感じになるらしい。

>>> sess.query(User).all()
2007-08-27 02:21:08,185 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
2007-08-27 02:21:08,186 INFO sqlalchemy.engine.base.Engine.0x..d0 []
[<User('test1', 'b444ac06613fc8d63795be9ad0beaf55011936ac')>,
 <User('test2', '109f4b3c50d7b0df729d299bc6f8e9ef9066971f')>,
 <User('test3', '3ebfa301dc59196f18593c45e519287a23297589')>,
 <User('test4', '1ff2b3704aede04eecb51e50ca698efd50a1379b')>,
 <User('test5', '911ddc3b8f9a13b5499b6bc4638a2b4f3f68bf23')>,
 <User('test6', 'a66df261120b6c2311c6ef0b1bab4e583afcbcc0')>,
 <User('test7', 'ea3243132d653b39025a944e70f3ecdf70ee3994')>,
 <User('test8', 'd03f9d34194393019e6d12d7c942827ebd694443')>,
 <User('test9', '53d525836cc96d089a5a4218b464fda532f7debe')>,
 <User('test10', '168f4029f416ee06565f12e697dfc1534ae69d32')>]

>>> # コレでもいける。
>>> for row in sess.query(User):
...    print row
2007-08-27 02:22:33,576 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
2007-08-27 02:22:33,577 INFO sqlalchemy.engine.base.Engine.0x..d0 []
<User('test1', 'b444ac06613fc8d63795be9ad0beaf55011936ac')>
<User('test2', '109f4b3c50d7b0df729d299bc6f8e9ef9066971f')>
<User('test3', '3ebfa301dc59196f18593c45e519287a23297589')>
<User('test4', '1ff2b3704aede04eecb51e50ca698efd50a1379b')>
<User('test5', '911ddc3b8f9a13b5499b6bc4638a2b4f3f68bf23')>
<User('test6', 'a66df261120b6c2311c6ef0b1bab4e583afcbcc0')>
<User('test7', 'ea3243132d653b39025a944e70f3ecdf70ee3994')>
<User('test8', 'd03f9d34194393019e6d12d7c942827ebd694443')>
<User('test9', '53d525836cc96d089a5a4218b464fda532f7debe')>
<User('test10', '168f4029f416ee06565f12e697dfc1534ae69d32')>

特定のデータを取り出すのにインデクシングしてみる。

>>> # 最初だけ取り出す。
>>> sess.query(User)[0]
2007-08-27 02:23:20,282 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
 LIMIT 1 OFFSET 0
2007-08-27 02:23:20,283 INFO sqlalchemy.engine.base.Engine.0x..d0 []
<User('test1', 'b444ac06613fc8d63795be9ad0beaf55011936ac')>

>>> # 最後だけ取り出す。
>>> sess.query(User)[-1]
2007-08-27 02:25:15,941 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
2007-08-27 02:25:15,942 INFO sqlalchemy.engine.base.Engine.0x..d0 []
<type 'exceptions.IndexError'>: list index out of range
>>> sess.query(User)[-2]
2007-08-27 02:26:05,141 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
2007-08-27 02:26:05,142 INFO sqlalchemy.engine.base.Engine.0x..d0 []
<User('test10', '168f4029f416ee06565f12e697dfc1534ae69d32')>

最後のデータを取り出すのにちょっと癖があるみたい。 しかも、最後のデータを取り出す形だと LIMIT, OFFSET が付かないらしい。 まぁ、可変長のデータに対してデータ取得前に長さが分かるはずないから当然だとは思う。

次にスライシングもやってみる。

>>> # 適当な範囲指定。
>>> sess.query(User)[1:5].all()
2007-08-27 02:30:12,270 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
 LIMIT 4 OFFSET 1
2007-08-27 02:30:12,270 INFO sqlalchemy.engine.base.Engine.0x..d0 []
[<User('test2', '109f4b3c50d7b0df729d299bc6f8e9ef9066971f')>,
 <User('test3', '3ebfa301dc59196f18593c45e519287a23297589')>,
 <User('test4', '1ff2b3704aede04eecb51e50ca698efd50a1379b')>,
 <User('test5', '911ddc3b8f9a13b5499b6bc4638a2b4f3f68bf23')>]

>>> # あえて範囲外を指定してみる。
>>> sess.query(User)[5:20].all()
2007-08-27 02:31:09,289 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
 LIMIT 15 OFFSET 5
2007-08-27 02:31:09,290 INFO sqlalchemy.engine.base.Engine.0x..d0 []
[<User('test6', 'a66df261120b6c2311c6ef0b1bab4e583afcbcc0')>,
 <User('test7', 'ea3243132d653b39025a944e70f3ecdf70ee3994')>,
 <User('test8', 'd03f9d34194393019e6d12d7c942827ebd694443')>,
 <User('test9', '53d525836cc96d089a5a4218b464fda532f7debe')>,
 <User('test10', '168f4029f416ee06565f12e697dfc1534ae69d32')>]

>>> # リミットをマイナス値指定。
>>> sess.query(User)[5:-2]
2007-08-27 02:33:32,609 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
2007-08-27 02:33:32,609 INFO sqlalchemy.engine.base.Engine.0x..d0 []
[<User(u'test6', u'a66df261120b6c2311c6ef0b1bab4e583afcbcc0')>,
 <User(u'test7', u'ea3243132d653b39025a944e70f3ecdf70ee3994')>,
 <User(u'test8', u'd03f9d34194393019e6d12d7c942827ebd694443')>]
>>> sess.query(User)[5:-1]
2007-08-27 02:35:16,456 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
2007-08-27 02:35:16,456 INFO sqlalchemy.engine.base.Engine.0x..d0 []
[<User(u'test6', u'a66df261120b6c2311c6ef0b1bab4e583afcbcc0')>,
 <User(u'test7', u'ea3243132d653b39025a944e70f3ecdf70ee3994')>,
 <User(u'test8', u'd03f9d34194393019e6d12d7c942827ebd694443')>,
 <User(u'test9', u'53d525836cc96d089a5a4218b464fda532f7debe')>]
>>> sess.query(User)[5:].all()
2007-08-27 02:37:55,613 INFO sqlalchemy.engine.base.Engine.0x..d0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users ORDER BY users.oid
 LIMIT -1 OFFSET 5
2007-08-27 02:37:55,616 INFO sqlalchemy.engine.base.Engine.0x..d0 []
[<User(u'test6', u'a66df261120b6c2311c6ef0b1bab4e583afcbcc0')>,
 <User(u'test7', u'ea3243132d653b39025a944e70f3ecdf70ee3994')>,
 <User(u'test8', u'd03f9d34194393019e6d12d7c942827ebd694443')>,
 <User(u'test9', u'53d525836cc96d089a5a4218b464fda532f7debe')>,
 <User(u'test10', u'168f4029f416ee06565f12e697dfc1534ae69d32')>]

インデクシングとスライシングとでリミットの挙動が違うのがちょっと気になる。 そんなものなのかなぁ?どうだろう?

細かいところが気になって全然進まないけど、継続して色々試していこう。 SQLを遅延評価してくれるところはかなり素敵。 all が付いたり付かなかったりしてるのもそのためっす。

Posted at: 
2007/08/27 02:53:46
0 Comments
0 TrackBacks
Tags: 
Python
SQLAlchemy
Trackback: 
http://humming.via-kitchen.com/2007/08/27/play-with-sqlalchemy-part2/trackback/

SQLAlchemyで遊んでみる。その1

前からちょくちょく弄っている SQLAlchemy なのですが、 ようやく 0.4(beta4) になったのでちょっと本腰入れて触ってみようと。 色々変わったところとかもあるみたいなので、 とりあえずもう1回ドキュメントを見ながら触ってみる。 って言いつつ、そのままやっても面白くないのでドキュメント半分・適当半分な訳ですが。

インストールは easy_install 経由で行った。 これが正しいのかは分からないけど。まぁ、入ったので良しとする。

$ sudo easy_install http://pypi.python.org/packages/source/S/SQLAlchemy/SQLAlchemy-0.4.0beta4.tar.gz#md5=97b00cfba5bcb7cc947320a66c2ce085

で、ドキュメントに書いてある通りにバージョン確認。

>>> import sqlalchemy
>>> sqlalchemy.__version__
'0.4.0beta4'

とりあえずインストールは上手くいってる模様なので、 ドキュメントを読み進めていく。 ココから復習・勉強スタート。

まずは engine 作って MetaData 作って。 ここらへんはインタープリタでやって誤字・脱字すると過激にやる気無くすので、 ファイルに書いてインポートする事に。 0.4からは ORM に関連する部分が sqlalchemy.orm に分かれたらしく、 基盤部分?とは別々にインポートする形になっているみたい。

# vim: fileencoding=utf-8 :

from datetime import datetime
from sqlalchemy import *
from sqlalchemy.orm import *


# 実行されたSQLを確認するためにecho=Trueにしておく。
engine = create_engine('sqlite:///tutorial.db', echo=True)

meta = MetaData(bind=engine)


# usersテーブルの定義。
users = Table('users', meta,
    Column('id', Integer, primary_key=True),
    Column('name', String(40), nullable=False),
    Column('password', String(40), nullable=False),
    Column('created_at', DateTime, nullable=False, default=datetime.now),
    Column('updated_at', DateTime, nullable=False, default=datetime.now, onupdate=datetime.now),
)


# usersのドメインオブジェクト作成。
class User(object):
    def __init__(self, name=None, password=None):
        self.name = name
        self.password = password

    def __repr__(self):
        return "<User(%r, %r)>" % (self.name, self.password)


# Userとusersの関連づける。
mapper(User, users)

コレをインタープリタで読み込む。 とりあえずデータベースへテーブル作成。

>>> # さっき作成したファイルのインポート。
>>> from tutorials import *

>>> # データベースへテーブル作成。
>>> meta.create_all()
2007-08-23 23:24:53,511 INFO sqlalchemy.engine.base.Engine.0x..b0 PRAGMA table_info("users")
2007-08-23 23:24:53,512 INFO sqlalchemy.engine.base.Engine.0x..b0 {}
2007-08-23 23:24:53,518 INFO sqlalchemy.engine.base.Engine.0x..b0
CREATE TABLE users (
        id INTEGER NOT NULL,
        name VARCHAR(40) NOT NULL,
        password VARCHAR(40) NOT NULL,
        created_at TIMESTAMP NOT NULL,
        updated_at TIMESTAMP NOT NULL,
        PRIMARY KEY (id)
)


2007-08-23 23:24:53,519 INFO sqlalchemy.engine.base.Engine.0x..b0 None
2007-08-23 23:24:53,529 INFO sqlalchemy.engine.base.Engine.0x..b0 COMMIT

ORMを操作する為には Session オブジェクトが必要なので作成する。

>>> Session = sessionmaker(bind=engine, autoflush=True, transactional=True)

>>> # この段階ではSessionクラス
>>> Session
<class 'sqlalchemy.orm.session.Sess'>

>>> # ココでインスタンス化
>>> sess = Session()
>>> sess
<sqlalchemy.orm.session.Sess object at 0x16c38d0>

ココで適当にUserオブジェクトを作成してみる。 パスワードを無駄にハッシュ化する為に sha もインポートしておく。

>>> import sha
>>> u1 = User('test1', sha.new('test1').hexdigest())
>>> u1
<User('test1', 'b444ac06613fc8d63795be9ad0beaf55011936ac')>

>>> # ココではまだデータベースへは登録されない。
>>> sess.save(u1)

>>> # ココでデータベースにアクセス
... # 一緒にINSERT文も走っているがコミットはされてない。
>>> sess.query(User).filter_by(name='test1').first()
2007-08-23 23:53:29,697 INFO sqlalchemy.engine.base.Engine.0x..f0 BEGIN
2007-08-23 23:53:29,751 INFO sqlalchemy.engine.base.Engine.0x..f0 INSERT INTO users (name, password, created_at, updated_at) VALUES (?, ?, ?, ?)
2007-08-23 23:53:29,752 INFO sqlalchemy.engine.base.Engine.0x..f0 ['test1', 'b444ac06613fc8d63795be9ad0beaf55011936ac', '2007-08-23 23:53:29.741694', '2007-08-23 23:53:29.741829']
2007-08-23 23:53:29,787 INFO sqlalchemy.engine.base.Engine.0x..f0 SELECT users.id AS users_id, users.name AS users_name, users.password AS users_password, users.created_at AS users_created_at, users.updated_at AS users_updated_at
FROM users
WHERE users.name = ? ORDER BY users.oid
 LIMIT 1 OFFSET 0
2007-08-23 23:53:29,789 INFO sqlalchemy.engine.base.Engine.0x..f0 ['test1']
<User('test1', 'b444ac06613fc8d63795be9ad0beaf55011936ac')>

>>> # u1のidを確認してみる。
>>> u1.id
1

ドキュメント通りにたくさん作成していく。

>>> sess.save(User('test2', sha.new('test2').hexdigest()))
>>> sess.save(User('test3', sha.new('test3').hexdigest()))
>>> sess.save(User('test4', sha.new('test4').hexdigest()))
>>> u1.password = sha.new('test1new').hexdigest()

>>> # ココでコミットをコール。
>>> sess.commit()
2007-08-24 00:04:40,053 INFO sqlalchemy.engine.base.Engine.0x..f0 UPDATE users SET password=?, updated_at=? WHERE users.id = ?
2007-08-24 00:04:40,053 INFO sqlalchemy.engine.base.Engine.0x..f0 ['2eecc02dc033e0aa85cd7a116626136bf4067d85', '2007-08-24 00:04:40.52547', 1]
2007-08-24 00:04:40,060 INFO sqlalchemy.engine.base.Engine.0x..f0 INSERT INTO users (name, password, created_at, updated_at) VALUES (?, ?, ?, ?)
2007-08-24 00:04:40,061 INFO sqlalchemy.engine.base.Engine.0x..f0 ['test2', '109f4b3c50d7b0df729d299bc6f8e9ef9066971f', '2007-08-24 00:04:40.60324', '2007-08-24 00:04:40.60424']
2007-08-24 00:04:40,072 INFO sqlalchemy.engine.base.Engine.0x..f0 INSERT INTO users (name, password, created_at, updated_at) VALUES (?, ?, ?, ?)
2007-08-24 00:04:40,074 INFO sqlalchemy.engine.base.Engine.0x..f0 ['test3', '3ebfa301dc59196f18593c45e519287a23297589', '2007-08-24 00:04:40.72284', '2007-08-24 00:04:40.72385']
2007-08-24 00:04:40,080 INFO sqlalchemy.engine.base.Engine.0x..f0 INSERT INTO users (name, password, created_at, updated_at) VALUES (?, ?, ?, ?)
2007-08-24 00:04:40,082 INFO sqlalchemy.engine.base.Engine.0x..f0 ['test4', '1ff2b3704aede04eecb51e50ca698efd50a1379b', '2007-08-24 00:04:40.80366', '2007-08-24 00:04:40.80466']
2007-08-24 00:04:40,089 INFO sqlalchemy.engine.base.Engine.0x..f0 COMMIT

もうちょっと試したいけど、とりあえずココまで。 次は Query とかセレクトで遊ぶ予定。

Posted at: 
2007/08/24 00:27:02
0 Comments
0 TrackBacks
Tags: 
Python
SQLAlchemy
Trackback: 
http://humming.via-kitchen.com/2007/08/24/play-with-sqlalchemy-part1/trackback/

Categories

Archives