1
1

More than 1 year has passed since last update.

FastAPI と Tortoise ORM と Pydantic について

Last updated at Posted at 2021-11-06

==>関連記事を書きました(2021/12/01)。FastAPI と SQLModel - Qiita

今回は、FastAPIでDBを使う方法を紹介します。ここではsqlite3を使用しますが、PostgreSQLやMySQLなども同様に使えるはずです。

FastAPIからDBを使う方法はいくつかありますが、ここではTortoise ORMというマッパーを使用します。DjangoのORMにインスパイヤーされたとありますが、Djangoよりは使いやすい気がします。しかしFastAPIはその根幹のところでPydantic クラスを採用していて、Tortoise ORMのクラスと重複してしまいますので両者のコンバートなどが必要になり少し面倒です。

FastAPIやPydantic、Tortoise ORMなどの基本的なところは以下の過去記事を参照してください。

【過去記事】
FastAPIで作るWebアプリ - 基本
FastAPIで作るWebアプリ - Body validation
Pydantic Data Model入門
Tortoise ORM入門

まずモデルの定義を行います。

model.py
from tortoise import fields
from tortoise.models import Model
from tortoise.contrib.pydantic import pydantic_model_creator

class Users(Model):
    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=100)
    age = fields.IntField()

User_Pydantic = pydantic_model_creator(Users, name="User")
UserIn_Pydantic = pydantic_model_creator(Users, name="UserIn", exclude_readonly=True)

ここで注意すべきことは、pydantic_model_creatorで、Tortoise ORMモデルからpydanticモデルを作成していることです。
User_Pydantic はUsersと同じフィールドを持ちますが、UserIn_Pydantic はidフィールドは持ちません。このことは後でSwgger UIで確認します。

以下がメインです。create_userの一つしかエンドポイントを持たない簡単なものです。

main.py
from fastapi import FastAPI
from model import User_Pydantic, UserIn_Pydantic, Users
from tortoise.contrib.fastapi import register_tortoise

app = FastAPI()


@app.post("/users", response_model=User_Pydantic)
async def create_user(user: UserIn_Pydantic):
    user_obj = await Users.create(**user.dict(exclude_unset=True))
    return await User_Pydantic.from_tortoise_orm(user_obj)


register_tortoise(
    app,
    db_url="sqlite://db.sqlite3",
    modules={"models": ["model"]},
    generate_schemas=True,
    add_exception_handlers=True,
)

create_user()の引数がUser_PydanticでなくUserIn_Pydanticの型であることに注意してください。Requestパラメータにはidは含まれないからです。

(1) Response Model

Response Model - FastAPI
@app.get()や@app.post()などのデコレーターのパスオペレーションの中にresponse_modelを宣言することができます。指定できるモデルはPydantic modelです。Pydantic modelのリスト[User_Pydantic]などもOKです。

response_modelを使う理由はデータをValidateしたり、ResponseのためのJSON Schemaを追加したり、output データを指定したmodelに制限するためです。

(2) model.dict(...)

model.dict(...) - Pydantic
Pydanticモデルをdictにコンバートするための方法です。
exclude_unset引数は、モデルを作成するときに明示的に値を指定されていないフィールドは排除される、というものです。デフォルト値とかですかね。

User_Pydantic.from_tortoise_ormはTortoiseモデルのオブジェクトをPydanticのオブジェクトに変換します。User_Pydantic.from_tortoise_orm(user_obj)をそのままreturnしているのは、Response Modelの宣言に即しています。

(3) register_tortoise

  • FastAPIのためのTortoiseの設定を行います。
  • modules={"models": ["model"]}でmodel.pyにモデルクラスが定義されていることを教えます。
  • generate_schemas=Trueで自動的にスキーマを生成します。
  • add_exception_handlers=Trueでカスタム例外ハンドラーをFastAPIに追加します。

Swgger UIでの検証

以下Swgger UIで簡単なテストを行いました。

RequestはUserIn_Pydantic型なのでidは含まれていません。

image.png

Response bodyを見ると、Response Modelが正しく動作しているのが確認できます。

image.png

試しにcreate_user()の引数をUser_Pydanticにしてみると、idが現れます。Requestにidを指定するのは、もちろん現実的な意味を持ちませんが。

image.png

今回の記事でFastAPIの基本的なところを押さえることができたのかな、と思います。が多分まだまだいろいろありますね。認証とか。

とりあえず今回は以上です。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1