本記事はPython初学者やFastAPIを学習したいと考えているWebエンジニア向けの入門者向けの記事になります。
この記事はFastAPIとPostgreSQLでモデル定義とMigrationを行う方法です。
Pythonのインストールから実施しますので安心して記事を進めてみてください。
Pythonの高速APIのFastAPIを利用するシーンが多くなってきました。
案件でも使用する機会が増えてきたのでノウハウと公開したいと思います。
すこし前ですとPythonでWebアプリを作成するのはDjango一択でした。
ですが最近ではJavaScriptのフレームワーク(特にReact)+FastAPIで開発することが増えています。
JavaScriptフレームワーク+APIの構成で優れていると感じることはネイティブアプリでもコードや環境を流用することができる点です。
性能的に遅いと言われるPythonで文字通り高速なFastAPIを学習していただければと幸いです。
- FastAPIとは?高速APIのメリット・デメリットを紹介!
- LinuxサーバーにFastAPIのインストールをする方法
- FastAPIでHello World。Pythonの爆速Webフレームワークを試してみよう!
- FastAPIでPostgreSQLに接続する方法
- FastAPI+PostgreSQLでモデル定義+Migration(今回の記事はここ)
- FastAPI+PostgreSQLでデータ参照。SELECT文を実行する方法
- FastAPI+PostgreSQLでデータ挿入。INSERT文を実行する方法
- FastAPI+PostgreSQLでデータ更新。UPDATE文を実行する方法
- FastAPI+PostgreSQLでデータ削除。DELETE文を実行する方法
- FastAPIのAPIドキュメント自動生成
- FastAPIでJWTトークン認証を実装してみよう!
pydanticとalembicの解説
pydanticとは?
pydanticとは、実行時における型ヒントを提供したり、データのバリデーション時のエラー設定を提供してくれるためのライブラリです。
FastAPIではSQLAlchemyを使用しデータベースのデータを操作する前に、モデルを定義する必要があり、モデル定義後バリデーションにpydanticを使用します。
参考:pydantic
alembicとは?
alembicとはSQLAlchemyのマイグレーションツールになります。
FastAPI以外でもSQLAlchemyを使用する際にはよく使用しますのでぜひこの機会に触ってみましょう。
参考:alembic
ファイル構成とディレクトリ構成の確認
前章のFastAPIでPostgresに接続する方法後、フォルダは以下の様になっています。
fastapi/
├ venv/
└ src/
├ database.py
├ main.py
├ models.py
└ schemas.py
この章で作成するファイルは以下になります。
- src/models.py
- src/schemas.py
Ubuntuの場合は「x86_64-linux-gnu-gcc」がないとエラーが出るのでライブラリ「python3-dev」をインストールします。
apt-get install build-essential libssl-dev libffi-dev python3-dev
必要なモジュールをインストールします。
cd fastapi
source venv/bin/activate
pip install psycopg2-binary
# pip install psycopg2
pip install pydantic
pip install alembic
まずはsrc/models.pyを作成しましょう。
from database import Base
import sqlalchemy as sa
class User(Base):
__tablename__ = "users"
user_id = sa.Column("user_id",
sa.Integer,
primary_key=True,
autoincrement=True)
name = sa.Column("name",
sa.Text,
nullable=False)
age = sa.Column("age",
sa.Integer,
nullable=False)
email = sa.Column("email",
sa.Text,
nullable=False)
次にsrc/schemas.pyを作成します。
from pydantic import BaseModel
class UserBase(BaseModel):
name: str
age: int
email: str
class Config:
orm_mode = True
alembicでマイグレーションの準備
alembicの初期化
まずはalembicに必要なファイルをinitializeします。
cd src/
alembic init alembic
initializeが完了するとalembicのファイル群が作成されます。
fastapi/
├ venv/
└ src/
├ alembic
│ ├ env.py
│ ├ README
│ ├ script.py.mako
│ └ versions/
├ alembic.ini
├ database.py
├ main.py
├ models.py
└ schemas.py
alembicの設定
次にalembicの設定を行います。
今回postgresのurlが動的に利用できるようにalembic.iniを使用しない構成をとります。
alembic.iniのURLをコメントアウトします。
# コメントアウト
# sqlalchemy.url = driver://user:pass@localhost/dbname
次にalembic/env.pyを修正します。
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
from database import Base, SQLALCHEMY_DATABASE_URL # 追記
import models # 追記
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
# target_metadata = None # 修正
target_metadata = models.Base.metadata # 追記
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
# コメントアウト
#url = config.get_main_option("sqlalchemy.url")
url = SQLALCHEMY_DATABASE_URL # 追記
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
configuration = config.get_section(config.config_ini_section)
configuration["sqlalchemy.url"] = SQLALCHEMY_DATABASE_URL
connectable = engine_from_config(
configuration,
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
# コメントアウト
# connectable = engine_from_config(
# config.get_section(config.config_ini_section),
# prefix="sqlalchemy.",
# poolclass=pool.NullPool,
# )
with connectable.connect() as connection:
context.configure(
connection=connection, target_metadata=target_metadata
)
with context.begin_transaction():
context.run_migrations()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
これでalembicの準備は完了です。
alembicでマイグレーション(Migration)実行
ではここからマイグレーションを実行していきましょう。
alembiceでのマイグレーションに必要なファイルの作成コマンドは以下になります。
alembic revision --autogenerate -m "create users table"
それでは実行してみましょう。
以下のように実行されればOKです。
# alembic revision -m "create user table"
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'users'
Generating /root/fastapi/src/alembic/versions/1f3b2391d90c_create_users_table.py ... done
次にsrc/alembic/versions/xxxxxxxx_create_user_table.pyが作成されているはずです。
作成されたpythonファイルを確認してみましょう。
"""create users table
Revision ID: 1f3b2391d90c
Revises:
Create Date: 2022-03-24 12:14:06.340797
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '1f3b2391d90c'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('users',
sa.Column('user_id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.Text(), nullable=False),
sa.Column('age', sa.Integer(), nullable=False),
sa.Column('email', sa.Text(), nullable=False),
sa.PrimaryKeyConstraint('user_id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('users')
# ### end Alembic commands ###
def upgrade()にusersテーブルを作成するためのコードが出力されています。
これでマイグレーションファイルの作成は完了です。
実際にマイグレーションを実行してみましょう。以下が実行コマンドになります。
alembic upgrade head
以下のように出力されているはずです。
# alembic upgrade head
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> 1f3b2391d90c, create tables
これでマイグレーションが完了して、テーブルが作成されました。
作成されたテーブルの確認
最後に本当にテーブルが作成されたか確認してみましょう。
postgresユーザにスイッチしてsqlコマンドでDBに接続してみます。
su - postgres
psql -U fastapi -h 127.0.0.1 -p 5432 fastapi
接続出来たら \dt でテーブルが作成されていることを確認しましょう。
su - postgres
psql -U fastapi -h 127.0.0.1 -p 5432 fastapi
Password for user fastapi:
psql (14.2 (Ubuntu 14.2-1.pgdg20.04+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.
fastapi=> \dt
List of relations
Schema | Name | Type | Owner
--------+-----------------+-------+---------
public | alembic_version | table | fastapi
public | users | table | fastapi
上記のようにusersテーブルが作成されていることを確認できました。
前回からの記事と本記事でデータベースの接続とマイグレーションが完了しました。
次は本格的にデータを参照してみたいと思います。
次の記事はこちら:FastAPI+PostgreSQLでデータ参照。SELECT文を実行する方法
前の記事はこちら:FastAPIでPostgreSQLに接続する方法