Installation and Quick Start in 5 Minutes
Instead of writing dozens of if-else lines just to check data types, let Pydantic handle it. This library helps you define clear, transparent, and extremely secure data structures.
Start with the familiar installation command:
pip install pydantic
Try creating a small script to validate user information. You’ll see the difference immediately:
from pydantic import BaseModel, ValidationError
class User(BaseModel):
id: int
username: str
email: str
is_active: bool = True
try:
# Note: id passed is a string "123"
user_data = {"id": "123", "username": "hoang_it", "email": "[email protected]"}
user = User(**user_data)
print(f"Valid User: {user.username} - ID: {user.id} (Type: {type(user.id)})")
except ValidationError as e:
print(e.json())
What just happened? Even though you passed id as the string "123", Pydantic automatically performed type coercion to int. If the data cannot be converted, it stops the error right at the “gateway” instead of letting it creep deep into your business logic.
Why is Pydantic v2 the Number One Choice?
When I first started out, I often used dict to hold data from APIs. The result was code riddled with if "key" in data:. Worse, the system would frequently crash in the middle of the night with a KeyError just because a partner API changed its structure without notice.
Pydantic solves this problem completely by forcing data to comply with a strict “contract” (Schema). Notably, version 2’s core was rewritten in Rust. According to popular benchmarks, its parsing speed is 5 to 50 times faster than version 1. When I processed a JSON file with 100,000 records, Pydantic v2 finished in a flash, significantly saving server resources.
Khai thác các tính năng cốt lõi
Smart Data Constraints with Field
Sometimes just specifying int or str isn’t enough. You need specific rules like: age must be over 18, or product price cannot be negative. This is where Field comes into play.
from pydantic import BaseModel, Field
class Product(BaseModel):
name: str = Field(..., min_length=3, max_length=50)
price: float = Field(..., gt=0) # Must be greater than 0
stock: int = Field(default=0, ge=0) # Greater than or equal to 0
product = Product(name="Mechanical Keyboard", price=150.5)
print(product)
The ... symbol (Ellipsis) indicates that this field is required. Your code now acts as both a filter and highly intuitive self-documenting guide.
Custom Validators: When the Rules Are Yours
Pydantic v2 provides two powerful tools: @field_validator and @model_validator. Suppose you need to match passwords during user registration:
from pydantic import BaseModel, field_validator, model_validator
class RegisterSchema(BaseModel):
username: str
password: str
confirm_password: str
@field_validator('username')
@classmethod
def no_spaces_in_username(cls, v: str):
if ' ' in v:
raise ValueError('Username cannot contain spaces')
return v
@model_validator(mode='after')
def check_passwords_match(self):
if self.password != self.confirm_password:
raise ValueError('Confirm password does not match')
return self
Handling Nested Models
Real-world data is often complex. An Order will contain a list of Products, and each product has its own Category. Pydantic handles this hierarchical structure very smoothly.
from typing import List
class Tag(BaseModel):
id: int
label: str
class Post(BaseModel):
title: str
tags: List[Tag]
data = {
"title": "Learning Pydantic v2",
"tags": [{"id": 1, "label": "Python"}, {"id": 2, "label": "Backend"}]
}
post = Post(**data)
print(post.tags[0].label) # Output: Python
When initializing Post, Pydantic automatically recurses to create internal Tag objects. If even one tag is missing an id field, the entire process will fail immediately. This ensures the data in your app is always 100% “clean”.
Data Export (Serialization)
After processing, you need to send the data. Pydantic v2 replaces the old dict() method with the more flexible model_dump().
model_dump(): Converts the model into a Python dictionary.model_dump_json(): Converts directly to a JSON string.
# Only include title and tags, ignore other fields
print(post.model_dump(include={'title', 'tags'}))
# Exclude fields with None or default values
print(post.model_dump(exclude_unset=True))
Real-world Application: When Should You Use It?
Based on my experience, there are 3 golden moments to introduce Pydantic into your project:
- Working with APIs: Whether it’s FastAPI, Flask, or Django, use Pydantic to control incoming Requests and outgoing Responses.
- Configuration Management (Settings): Combine with
pydantic-settingsto safely read environment variables (ENV). - Data Migration: I once used Pydantic to migrate 50,000 rows of old CSV data to PostgreSQL. Pydantic pointed out exactly which row and column had the wrong format, saving me an entire day of debugging.
Pro Tips for Code Optimization
Using Aliases: If a third-party API returns keys like First-Name (violating Python variable naming conventions), use alias to map the data smoothly.
Strict Mode: If you want to enforce strict discipline and disallow automatic type coercion (e.g., preventing "123" from becoming 123), enable strict=True.
Pydantic v2 is not just a validation library; it is the new standard for writing professional Python code. Start applying it today to protect your system from silly data errors.

