SQLAlchemy入門 メタデータによるスキーマの定義

メタデータ(スキーマ定義言語、SDL)

メタデータとは、テーブルのスキーマをPythonのコード上で定義する方法です。DBMSに依存しない方法でスキーマを記述することができるのが大きなメリットといえるでしょう。

スキーマの定義

まずは、サンプルから見てみてください。

from sqlalchemy import Table, Column, Integer, String, MetaData

meta = MetaData()
users = Table('Users', meta,
              Column('id', Integer, primary_key=True),
              Column('name', String),
              Column('age', Integer)
              )

TableクラスでDBテーブルのスキーマを定義することができます。また、Columnオブジェクトでテーブルを構成するカラムを定義することができます。
上のサンプルでは、カラムとして、id、name、ageを持つUsersテーブルのスキーマをメタデータを使用して記述しています。

定義の確認

cもしくはcolumnsでカラム名や属性を確認できます。先ほどのUSERSテーブルの属性などを確認してみましょう。

from sqlalchemy import Table, Column, Integer, String, MetaData

meta = MetaData()
users = Table('Users', meta,
              Column('id', Integer, primary_key=True),
              Column('name', String),
              Column('age', Integer)
              )

# Usersテーブルの確認
print(meta.tables['Users'])

# すべてのテーブルの確認
for table in meta.tables:
    print(table)

# columns、もしくはcでカラム名の参照が可能
print(users.columns.name)
print(users.c.name)

# すべてのカラムの確認
for col in users.c:
    print(col)

# primary_keyで主キーを参照可能
for pk in users.primary_key:
    print(pk)

# その他のカラムの属性の確認
print(users.c.id.name)
print(users.c.id.type)
print(users.c.id.nullable)
print(users.c.id.primary_key)

以下、サンプルの解説です。

テーブル情報の取得

meta.tablesにすべてのテーブル情報が辞書形式で格納されています。

カラムの確認

テーブルオブジェクトにはcもしくはcolumnsという属性があり、そこでカラムの情報を参照することができます。
また、29行目以降にありますが、c.カラム名.のあと、type、nullable、primary_keyなどのカラムの属性を参照することができます。

メタ情報を反映させる

さて、ここからが重要です。先ほど定義したメタデータですが、engineオブジェクトと連携することにより実際のデータベスに反映することができます。

from sqlalchemy import Table, Column, Integer, String, MetaData, create_engine

engine = create_engine('sqlite:///:memory:')
meta = MetaData(engine)
users = Table('Users', meta,
              Column('id', Integer, primary_key=True),
              Column('name', String),
              Column('age', Integer)
              )

# metaデータの内容をデータベースに反映
meta.create_all()

with engine.connect() as con:
    # DBアクセスして確認する

    # 投入データの定義
    rows = ({"id": 1, "name": "Sato", "age": 31},
            {"id": 2, "name": "Suzuki", "age": 18},
            {"id": 3, "name": "Yamada", "age": 40},
            {"id": 4, "name": "Kuro", "age": 30},
            )

    # Insert文を実行
    for row in rows:
        con.execute("INSERT INTO USERS (id, name, age) VALUES(:id, :name, :age)", row)

    # Select文を実行する
    rows = con.execute("SELECT * FROM USERS")
    for row in rows:
        print(row)

MetaDataの引数にengineオブジェクトを指定します。meta.create_all()でテーブル定義の内容をデータベスに反映させることができます。14行目以降は前回行ったSQLのサンプルと同様です。Create文を実行しなくてもテーブルが生成されていることがポイントです。

特定のテーブルだけ生成する場合は以下のようにテーブルオブジェクトのcreateメソッドを呼び出します。

users.create()

また、テーブルを削除する場合はdropメソッドを使用します。

users.drop()

メタ情報を生成する

逆にすでに存在するテーブルからメタ情報を生成することも可能です。この操作をリフレクションと呼びます。

from sqlalchemy import MetaData, create_engine

engine = create_engine('sqlite:///db.sqlite')
meta = MetaData(engine, reflect=True)

# Usersテーブルのカラムの確認
for col in meta.tables['Users'].columns:
    print(col)

サンプルでは、db.sqliteというデータベースに接続後、メタデータの引数でreflect=Trueを指定することにより自動的にデータベースのテーブル情報がメタデータに格納されていることが確認できます。

また、リフレクションは後からでも実行可能です。

meta.reflect(bind=engine)