前回の記事「FastAPIで作るWebアプリ - Body validation」でも少し触れましたが、FastAPIのData validationには全面的にPydanticが採用されています。
**Pydanticはpythonのtype annotationsを利用した、Data validation を提供します。**pydantic はruntime時にtype hintsを使い、Dataがinvalid時にユーザフレンドりなerrorsを吐き出してくれます。
今回は、FastAPIから離れて、純粋にPydanticとはどんなものかを見ていきます。
【過去記事】
Python Asyncio入門
Aiohttpで作るSimple Web Server - Qiita
Starletteで作る Simple Web Server - QIita
FastAPIで作るWebアプリ - 基本
FastAPIで作るWebアプリ - validation
FastAPIで作るWebアプリ - Body validation
FastAPIで作るWebアプリ - Form validation
Pydantic Data Model入門
Tortoise ORM入門
#1. 基本
PydanticではまずModel(データのスキーマみたいなもの)を作成します。そしてModelのインスタンスを作成するときにvalidationが行われます。エラーがないときはそのままインスタンスが作成されますが、エラーがあるときは例外を投げてくれます。
以下の例では、BaseModelを使ってModelを作成します。またValidationErrorで例外を受けています。
from pydantic import BaseModel,ValidationError
class User(BaseModel):
id: int
name = 'Jane Doe'
user1 = User(id='123')
print(user1)
user2 = User(id='456')
print(user2)
user3 = User(id=789,name='Jhon Lennon')
print(user3)
try:
user4 = User(id='abc')
print(user4)
except ValidationError as e:
print(e.json())
エラーは以下のようにわかり易いものとなっています。"loc"はエラーの場所を示し、"msg"と"type"でエラーの内容がわかるようになっています。
id=123 name='Jane Doe'
id=456 name='Jane Doe'
id=789 name='Jhon Lennon'
[
{
"loc": [
"id"
],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
]
2. いろいろなData型
from enum import Enum
from datetime import datetime
from typing import List, Optional
from pydantic import BaseModel
class Gender(str, Enum):
male = 'male'
female = 'female'
other = 'other'
not_given = 'not_given'
class User(BaseModel):
id: int
name = 'John Doe'
gender: Gender
signup_ts: Optional[datetime] = None
friends: List[int] = []
external_data = {
'id': '123',
'gender': 'male',
'signup_ts': '2019-06-01 12:22',
'friends': [1, 2, '3'],
}
user = User(**external_data)
print(user.dict())
- id はint型です。型が指定してあるだけなので id は必須となります。Strings, bytes または floats の値が指定されると、可能であれば、型変換されます。それ以外は例外が発生します。
- nameはstringのdefault値が指定されているので、stringであると型推論されます。defaultが指定されているので必須ではありません。
- genderはEnum classであるGenderの値をとります。'mail', 'femail', 'other', 'not_given' 以外は例外が発生します。
- signup_ts は、datetime型またはNone、を許容する型となります(Optionalの定義より)。defaultはNoneとなります。
- friends はint型の値のリストとなります。int型に変換可能な値は自動的に変換されます。
これを動かすと以下のprint文が表示されます。
{'id': 123, 'gender': <Gender.male: 'male'>, 'signup_ts': datetime.datetime(2019, 6, 1, 12, 22), 'friends': [1, 2, 3], 'name': 'John Doe'}
それではexternal_dataの値に不正値を入れて、ちゃんとエラーになることを確認してみます。
まずgenderの値を変えてみます
external_data = {
'id': '123',
'gender': 'woman',
'signup_ts': '2019-06-01 12:22',
'friends': [1, 2, '3'],
}
ちゃんとエラーになりますね
pydantic.error_wrappers.ValidationError: 1 validation error for User
gender
value is not a valid enumeration member; permitted: 'male', 'female', 'other', 'not_given' (type=type_error.enum; enum_values=[<Gender.male: 'male'>, <Gender.female: 'female'>, <Gender.other: 'other'>, <Gender.not_given: 'not_given'>])
次にsignup_tsの時刻指定を25時にしてみます
external_data = {
'id': '123',
'gender': 'male',
'signup_ts': '2019-06-01 25:22',
'friends': [1, 2, '3'],
}
ちゃんと怒ってくれます。
pydantic.error_wrappers.ValidationError: 1 validation error for User
signup_ts
invalid datetime format (type=value_error.datetime)
最後にfriendsのリストにint変換できない文字列を入れてみます
external_data = {
'id': '123',
'gender': 'male',
'signup_ts': '2019-06-01 12:22',
'friends': [1, 2, 'not number'],
}
やはりエラーとなります。
pydantic.error_wrappers.ValidationError: 1 validation error for User
friends -> 2
value is not a valid integer (type=type_error.integer)
今回は以上です