FastApi で CRUD を試して見た時のメモ
前回の記事で API と Render について触れました。
今回はデータベースにつないで CRUD を試してみたいと思います。
環境は Docker を使ってアプリケーションとデータベースのコンテナを分けています。
参考
階層
階層は下の通りです。
project
├── backend
│ ├── db.py # 作成
│ ├── main.py # 編集
│ ├── models.py # 作成
│ ├── schemas.py # 作成
│ ├── static
│ │ └── styles.css
│ ├── templates
│ │ └── main.html
│ └── user.py # 作成
├── database
├── frontend
├── mysql
├── docker-compose.yml
├── dockerfile
└── requirements.txt
インストール
前回に続いてデータベース関連のライブラリをインストールします。
Django では ORM が備わっていますが、FastApi は無いのでインストールが必要のようです。
sqlalchemy は、スターが一番多いよう。
pip install sqlalchemy pymysql
前回の記事も合わせると requirements.txt は下記のようになりました。
anyio==3.6.1
click==8.1.3
fastapi==0.81.0
greenlet==1.1.3
h11==0.13.0
httptools==0.4.0
idna==3.3
Jinja2==3.1.2
MarkupSafe==2.1.1
pydantic==1.10.1
PyMySQL==1.0.2
python-dotenv==0.21.0
PyYAML==6.0
sniffio==1.3.0
SQLAlchemy==1.4.40
starlette==0.19.1
typing_extensions==4.3.0
uvicorn==0.18.3
uvloop==0.16.0
watchfiles==0.16.1
websockets==10.3
docker-compose の設定
docker-compose の一部を切り出して記載しておきます。
ここでデータベースとユーザーの情報を定義しています。
version: '3'
services:
...(略)...
db:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: database_name
MYSQL_USER: user_name
MYSQL_PASSWORD: user_password
MYSQL_ROOT_PASSWORD: root_user_password
ports:
- 33306:3306
...(略)...
データベース接続
データベース接続には db.py で定義するようです。
from sqlalchemy import create_engine, MetaData
engine = create_engine(
'mysql+pymysql://user_name:user_password@db:3306/database_name')
meta = MetaData()
conn = engine.connect()
テーブル設計
テーブル設計は models.py で定義するようです。
from sqlalchemy import Table, Column, Integer, String
from db import meta, engine
users = Table('users', meta,
Column('id', Integer, primary_key=True, autoincrement=True),
Column('name', String(255)),
Column('email', String(255)),
Column('password', String(255)))
meta.create_all(engine)
型の指定
リクエストやレスポンスの型を定義しているようです。
from pydantic import BaseModel
class User(BaseModel):
name: str
email: str
password: str
ルーティング
main.py に app.include_router(user) を定義して、uses.py にルーティング出来るようにします。
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from user import user
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")
@app.get("/", response_class=HTMLResponse)
async def render_main(request: Request):
return templates.TemplateResponse("main.html", {"request": request, "message": "Hello RestApi"})
app.include_router(user)
処理
main.py から流れてきて実際に処理をしてレスポンスを返します。
CRUD それぞれの処理が書かれています。
from fastapi import APIRouter
from models import users
from db import conn
from schemas import User
user = APIRouter()
@user.get('/user/')
async def fetch_users():
return conn.execute(users.select()).fetchall()
@user.get('/user/{id}')
async def fetch_user(id: int):
return conn.execute(users.select().where(users.c.id == id)).first()
@user.post('/user/')
async def create_user(user: User):
conn.execute(users.insert().values(
name=user.name,
email=user.email,
password=user.password
))
return conn.execute(users.select()).fetchall()
@user.put('/user/{id}')
async def update_user(id: int, user: User):
conn.execute(users.update().values(
name=user.name,
email=user.email,
password=user.password
).where(users.c.id == id))
return conn.execute(users.select()).fetchall()
@user.delete('/user/{id}')
async def delete_user(id: int):
conn.execute(users.delete().where(users.c.id == id))
return conn.execute(users.select()).fetchall()
確認
- http://localhost:8000/docs にアクセスする。
- POST /user/ Create User をクリックして開く。
- Try it out をクリックする。
- JSON が表示されるので値を適当に修正する。
- Execute をクリックする。
- テーブル users の中身を確認する。
mysql> SELECT * FROM users;
+----+------+-------+----------+
| id | name | email | password |
+----+------+-------+----------+
| 1 | hoge | fuga | bar |
+----+------+-------+----------+
1 row in set (0.00 sec)
ディスカッション
コメント一覧
まだ、コメントがありません