8
4

More than 1 year has passed since last update.

Pydantic Data Model入門

Last updated at Posted at 2021-11-03

前回の記事「FastAPIで作るWebアプリ - Body validation」でも少し触れましたが、FastAPIのData validationには全面的にPydanticが採用されています。

**Pydanticはpythonのtype annotationsを利用した、Data validation を提供します。**pydantic はruntime時にtype hintsを使い、Dataがinvalid時にユーザフレンドりなerrorsを吐き出してくれます。

Pydantic 公式サイト

今回は、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で例外を受けています。

example.py
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型

example2.py
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)

今回は以上です

8
4
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
8
4