読者です 読者をやめる 読者になる 読者になる

0.3から0.4へ(3)

SQLAlchemy

今日学習したことのメモ。0.4のバグ?

defaultの動作が変わった

次のようなテーブルを定義したとします。

cat_table = Table('cat', metadata,
                  Column('id', Integer, primary_key=True),
                  Column('name', Unicode(100), nullable=False),
                  Column('created_at',
                         DateTime,
                         nullable=False,
                         default=func.now()
                         ),
                  Column('updated_at',
                         DateTime, nullable=True,
                         onupdate=func.now()
                         )
                  )

class Cat(object):
    def __init__(self, name):
        self.name = name

mapper(Cat, cat_table)

0.3で新しくオブジェクトを生成し、永続化した場合、

    sess = create_session(bind_to=engine)
    cat = Cat(u'Rudolf')
    sess.save(cat)
    sess.flush()

    # 生成時間がとれる
    assert cat.created_at is not None

次のようなクエリが実行されます。

BEGIN
/* 一度データベースの現在時刻を取得 */
SELECT now()
/* パラメータは['Rudolf', datetime.datetime(2007, 9, 28, 19, 10, 27), None] */
INSERT INTO cat (name, created_at, updated_at) VALUES (%s, %s, %s)
COMMIT

一方、0.4で新しくオブジェクトを生成、永続化した場合、

    sess = Session()
    cat = Cat(u'Rudolf')
    sess.save(cat)
    sess.commit()

    # 失敗:前まで生成時間がとれていたはずなのに・・・
    assert cat.created_at is not None

次のようなSQLが実行されます。余計なSELECT文は実行されません。

BEGIN
/* パラメータは['Rudolf', None] */
INSERT INTO cat (name, created_at, updated_at) VALUES (%s, now(), %s)
COMMIT

この影響からか、0.4ではColumnオブジェクトのdefaultで指定した値がとれなくなってしまいました。
この辺のドキュメントをまだあまり確認していませんが、あまり期待している動作ではないような・・・

ただし、0.4でもdefaultにPython関数を指定してやると、0.4でも期待通り?の動作をします。

from datetime import datetime

cat_table = Table('cat', metadata,
                  Column('id', Integer, primary_key=True),
                  Column('name', Unicode(100), nullable=False),
                  Column('created_at',
                         DateTime,
                         nullable=False,
                         default=datetime.now   # 変更
                         ),
                  Column('updated_at',
                         DateTime, nullable=True,
                         onupdate=datetime.now   # 変更
                         )
                  )