バリデーション(Pydantic)¶
モデル分離 の最後で「EmailStr や Field(max_length=...) でバリデーションできる」と書いた。
ここでは Pydantic のデータバリデーション・ field_validator ・ computed_field を見ていく。
Pydanticによるデータバリデーションの基本¶
例えば User クラスを普通の class で作って、データのバリデーションもしようとすると、こうなる。めんどくさい……
# 普通の class でバリデーションする場合
class User:
def __init__(self, name: str, email: str, age: int):
if not isinstance(name, str):
raise TypeError("name must be str")
if len(name) > 255:
raise ValueError("name must be 255 characters or fewer")
if not isinstance(age, int):
raise TypeError("age must be int")
if not (18 <= age <= 100):
raise ValueError("age must be between 18 and 100")
self.name = name
self.email = email
self.age = age
alice = User("Alice", "alice@example.com", 30)
print(alice.name)
print(alice.email)
print(alice.age)
Pydantic を使えば、かなりスッキリする。 EmailStr みたいに import するだけで使えるバリデーション用の型もたくさんある。
# Pydantic を使う場合
from pydantic import BaseModel, EmailStr, Field
class User(BaseModel):
name: str = Field(max_length=255)
email: EmailStr
age: int = Field(ge=18, le=100)
alice_data = {
"name": "Alice",
"email": "alice@example.com",
"age": 30,
}
alice = User(**alice_data)
print(alice.name)
print(alice.email)
print(alice.age)
EmailStr を使うには
EmailStr は email-validator が必要。 fastapi[standard] を入れていれば一緒に入ってるけど、素の Pydantic だけで使うなら uv add "pydantic[email]" で入れる。
例えば alice_data の email を alice-example.com ( @ を - に変更)にするとエラーになる。
Traceback (most recent call last):
...
pydantic_core._pydantic_core.ValidationError: 1 validation error for User
email
value is not a valid email address: An email address must have an @-sign. [type=value_error, input_value='alice-example.com', input_type=str]
Pydantic の BaseModel でモデルを作って、それをエンドポイントの引数にしておけば、入ってくるデータのバリデーションができる。
Field validators¶
例えば下記のようなモデルを定義したとすると、これだとパスワードの長さだけをバリデーションできる。
class UpdatePassword(SQLModel):
current_password: str = Field(min_length=12, max_length=128)
new_password: str = Field(min_length=12, max_length=128)
ここにパスワードの複雑さチェック( zxcvbn )も追加したい、となったら field_validator が使える。
zxcvbn をインストールしてから。
# models.py の UpdatePassword
from pydantic import field_validator
from sqlmodel import SQLModel, Field
from zxcvbn import zxcvbn
def _validate_password_complexity(password: str) -> str:
"""パスワードの複雑さをチェックする"""
results = zxcvbn(password)
if results["score"] < 3:
warning = results["feedback"]["warning"] or "Password is too simple."
raise ValueError(f"Insufficient security strength: {warning}")
return password
class UpdatePassword(SQLModel):
current_password: str = Field(min_length=12, max_length=128)
new_password: str = Field(min_length=12, max_length=128)
@field_validator("new_password")
@classmethod
def check_strength(cls, v: str) -> str:
return _validate_password_complexity(v)
Info
@field_validator("new_password") で、 new_password フィールドに対して check_strength を実行する。 score が低いと ValueError を投げるので、 new_password が弱いパスワードだと ValidationError になる。
Note
上の書き方だと、 field_validator は Pydantic の標準バリデーション(型・長さ)の後に実行される(デフォルトで mode="after" )。
cf. https://docs.pydantic.dev/latest/concepts/validators/#field-validators
computed_field decorator¶
models.py などで定義したクラスのフィールドを加工して返したいときに使える。
下の例は、 first_name ・ last_name は大文字小文字をそのまま扱うけど、 full_name は大文字に加工して返している。