概要
過去にflask-pydanticを使った方法を紹介しました
しかし flask-pydantic は V2 に対応していません
今回は flask-pydantic なしで Flask + pydantic を連携する方法を考えます
環境
- macOS 11.7.10
- Python 3.11.6
- flask 3.0.0
- pydantic 2.5.3
案1: ルーティング内の先頭でモデルを使用する
from flask import Flask, jsonify, request
from pydantic import BaseModel, field_validator
app = Flask(__name__)
class User(BaseModel):
name: str
@field_validator("name")
@classmethod
def validate_name(cls, v):
if v != "hawk":
raise ValueError()
return v
@app.route("/", methods=["POST"])
def test():
data = request.json
if data is None:
raise ValueError()
user = User(**data)
return jsonify(user.model_dump())
メリット
- 簡単、明瞭、特に何も考えず先頭で変換するだけなので楽
デメリット
- 変換する部分の実装を忘れそう
- request.json から変換しているが他にも query や path などをモデルに変換する部分の考慮しなければならない
案2: デコレータを使い引数で受け取る
from flask import Flask, jsonify, request
from pydantic import BaseModel, field_validator
app = Flask(__name__)
class User(BaseModel):
name: str
@field_validator("name")
@classmethod
def validate_name(cls, v):
if v != "hawk":
raise ValueError()
return v
def validate(func):
def wrapper(*args, **kwargs):
data = request.json
if data is None:
raise ValueError()
user = User(**data)
return func(user, *args, **kwargs)
return wrapper
@app.route("/", methods=["POST"])
@validate
def test(user: User):
return jsonify(user.model_dump())
メリット
- ルーティング側での変換が不要になるのでコードがきれいになる
- 引数で受け取れてかつ検証済みのオブジェクトなので安全に扱える
デメリット
- デコレータが肥大化しないように気をつける必要がある
- モデルごとにデコレータを追加する必要がないようにする必要がある
- request.json から変換しているが他にも query や path などをモデルに変換する部分の考慮しなければならない
最後に
頑張れば何とかなりそうだけどコードが複雑化しないように工夫する必要がありそうです
そのあたりを吸収してくれてくれているのが flask-pydantic なので最悪ライブラリを自分でメンテするのもありなのかもしれません
0 件のコメント:
コメントを投稿