SQLAlchemyでテーブルをつくろうと思ったが、予想以上にハマったのでメモ。
テーブル定義
テーブルは、Baseを継承したクラスで定義する。(複数の方法があるようだがコレに統一)
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String(255))
password = Column(String(255))
declarative_baseを実行してBaseクラスを作成する。クラス定義はコレを継承。
__tablename__
でテーブル名を決めることが可能。
「クラス名は単数、テーブル名は複数」というRailsっぽい事も可能になる。
テーブルの作成(基本)
テーブルの作成は、metadata.create_all
で一括して行うのが基本
engine = create_engine("mysql+pymysql://<user>:<pass>@<host>/<dbname>?charset=utf8")
Base.metadata.create_all(bind=engine)
上記で作成したBaseクラスのmetadata.create_all
に、データベースエンジンを渡す。
これによりBaseを継承しているテーブル群が、一括してCREATE TABLEされる。
エンジンの作成は、公式ドキュメントが詳しい。別途、PyMySQLのようにデータベースクライアントが必要。
テーブル再作成
create_allは一度実行すると二回目以降は実行されない。このため、別途SQLなどでテーブルを削除した後、再度実行してもテーブルが作られない。
この場合は、引数で、checkfirst=False
とする。
Base.metadata.create_all(bind=engine, checkfirst=False)
テーブルを指定して作成したい
create_allは一括でテーブルをつくってくれるが、テーブルを指定して作成した場合もある。
この場合は、tables引数にテーブル情報を渡すことで可能になる。
テーブル情報は、テーブル定義クラスの__table__
プロパティに入っている。
Base.metadata.create_all(bind=engine, tables=[User.__table__])
気をつけたいポイントとしては、tablesには配列で渡すコトと、__table__
プロパティを渡すこと。
create_allにテーブルを指定するのは、名前的にシックリこない…… が仕方がない。
primary_keyを連番にしたくない
他所のデータベースからデータを手元に持ってきて、ゴニョゴニョしたいときなどは、primary_keyを連番にしたくない。
primary_keyを連番にはしたくない場合は、autoincrement
をFalse
で指定する。
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True, autoincrement=False)
name = Column(String)
fullname = Column(String(255))
password = Column(String(255))