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

0.3から0.4へ

SQLAlchemy

SQLAlchemy0.3で作ったアプリケーションを、0.4に移行しようとしています。
今日学習したことのメモです。

DynamicMetaDataはなくなった

0.4からDynamicMetaDataはなくなったので、MetaDataを使います。またテーブル定義時に、必ずMetaDataのインスタンスを渡さなくてはならないようです。(ドキュメントを確認したわけではないから自信なし。)

from sqlalchemy import *

metadata = MetaData()

cat_table = Table('cat', metadata,
                        Column('id', Integer, primary_key=True),
                        Column('name', Unicode(50), nullable=False),
                        mysql_engine='InnoDB'
                        )

sqlalchemy.ormからORM関連の関数をインポートしなくてはならない

mapper, relation, backrefなどの関数はsqlalchemy.ormからインポートしなくてはなりません。"from sqlalchemy import *"ではインポートされません。

engine_from_configという関数がある

昔からあるのかもしれませんが、engine_from_configという関数があり、辞書型オブジェクトからEngineオブジェクトを生成する際に便利です。

from sqlalchmey import engine_from_config

engine = engine_from_config(dict(url='mysql://user:pass@localhost/test?charset=utf8',
                                           echo=True,
                                           pool_recycle=3600))

0.4でも、sqlalchemy.engine.url.URLオブジェクトはそのままなので、これを使ってEngineオブジェクトを作ることも出来ます。
僕がDjango+SQLAlchemyで使っている実際のコードは次のような感じ。

import sqlachemy
from django.conf import settings

def create_engine():
    url = URL(drivername=settings.DATABASE_ENGINE,
              database=settings.DATABASE_NAME,
              username=settings.DATABASE_USER,
              password=settings.DATABASE_PASSWORD,
              host=settings.DATABASE_HOST,
              port=settings.DATABASE_PORT or None,
              query = getattr(settings, 'DATABASE_OPTIONS', {})
              )

    # settings.pyに
    # SQLALCHEMY_OPTIONS = dict(pool_recylcle=3600, echo=False)
    # のように定義しています。
    options = getattr(settings, 'SQLALCHEMY_OPTIONS', {})
    engine = sqlalchemy.create_engine(url, **options)
    return engine

Pylonsのwikiにもありますが、MySQLを使う場合、pool_recycleを指定することは重要です。これを指定していないと、しばらく接続を使わない場合(mysqldの設定にもよりますがデフォルトでは8時間のようです)、"MySQL server has gone away"というエラーが発生します。

session_contextはなくなった

代わりにsqlalchemy.orm.scoped_sessionを使い、アプリケーション内で使うSessionクラスを定義します。

from sqlalchemy.orm import scoped_session, sessionmaker

Session = scoped_session(sessionmaker(transactional=True, autoflush=True, bind=create_engine()))

現在のセッションを初期化したいとき

0.3では、

session_context.current.clear()

のような処理を行っていましたが、0.4では次のようにするようです。

Session.remove()

Djangoで使うならば、dispatcherを使って次のようにするとか?(あまりテストしていなので自信なし。)

from django.core import signals
from django.dispatch import dispatcher

def end_request(signal, sender):
    Session.remove()

dispatcher.connect(receiver=end_request,
                   signal=signals.request_finished)

Sessionオブジェクトのライフサイクルについては、本家ドキュメントにあたるのが一番手っ取り早いです。

直にSQLを実行したい場合

Session.executeが使えます。

Session.execute("SELECT * FROM cat")

assignmapperはなくなった

頭が痛い・・・