Complete Guide to Using Pydantic: Data Validation Made Easy
Pydantic is a powerful Python library for data validation and settings management using Python type hints. It's extremely popular in the modern Python ecosystem, especially used by FastAPI, and has become the de-facto standard for data validation.
In this tutorial, we'll learn Pydantic from basics to advanced usage with practical examples.
Why Pydantic?
Pydantic Advantages:
Installation
Install Pydantic v2 (Latest)
# Install Pydantic v2
pip install pydantic
Install with email validation
pip install "pydantic[email]"
Install with dotenv support
pip install "pydantic-settings"
Verify Installation
import pydantic
print(f"Pydantic version: {pydantic.version}")
Should print 2.x.x
Basic Usage: Your First Model
1. Simple Model
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str
email: str
age: int
Create instance
user = User(id=1, name="Ruby", email="ruby@rubythalib.ai", age=25)
print(user)
Output: id=1 name='Ruby' email='ruby@rubythalib.ai' age=25
print(user.modeldump())
Output: {'id': 1, 'name': 'Ruby', 'email': 'ruby@rubythalib.ai', 'age': 25}
2. Automatic Type Conversion
Pydantic automatically converts compatible data types:
from pydantic import BaseModel
class Product(BaseModel):
id: int
name: str
price: float
instock: bool
Strings will be converted to int and float
product = Product(
id="123", # String -> int
name="Laptop",
price="15000000", # String -> float
instock="yes" # String -> bool
)
print(product.id, type(product.id))
Output: 123
print(product.price, type(product.price))
Output: 15000000.0
print(product.instock, type(product.instock))
Output: True
3. Validation Errors
from pydantic import BaseModel, ValidationError
class User(BaseModel):
id: int
name: str
age: int
try:
user = User(id="notanumber", name="Ruby", age=25)
except ValidationError as e:
print(e)
# Will print detailed error about invalid id
Output:
1 validation error for User
id
Input should be a valid integer, unable to parse string as an integer [type=intparsing, inputvalue='notanumber', inputtype=str]
Field Types and Constraints
1. Optional Fields
from typing import Optional
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str
email: Optional[str] = None # Optional with default None
phone: str | None = None # Python 3.10+ syntax
user1 = User(id=1, name="Ruby")
print(user1.email) # None
user2 = User(id=2, name="Ahmad", email="ahmad@example.com")
print(user2.email) # ahmad@example.com
2. Default Values
from pydantic import BaseModel
class Product(BaseModel):
id: int
name: str
price: float = 0.0
category: str = "General"
instock: bool = True
product = Product(id=1, name="Notebook")
print(product.modeldump())
{'id': 1, 'name': 'Notebook', 'price': 0.0, 'category': 'General', 'instock': True}
3. Field with Constraints
from pydantic import BaseModel, Field
class User(BaseModel):
id: int = Field(gt=0, description="User ID must be positive")