Welcome, @name! Darwin here with Pydantic - the most powerful data validation system in Python! 📊✅
Pydantic is the core of FastAPI - every request/response goes through Pydantic validation. In version 2.0 it was rewritten in Rust and is 17x faster! ⚡🦀
Safari Analogy: Pydantic is like a quality control system for observations - it checks whether each observation has correct data (species exists, population is a number, date is valid). If something is wrong, it reports an error immediately! 🔍✅
1from pydantic import BaseModel
2
3class Species(BaseModel):
4 id: int
5 name: str
6 population: int
7 endangered: bool = False # Default value
8
9# Creating an instance
10lion = Species(id=1, name="Lion", population=120, endangered=True)
11
12print(lion.name) # "Lion"
13print(lion.dict()) # {'id': 1, 'name': 'Lion', 'population': 120, 'endangered': True}
14print(lion.json()) # JSON string1# Pydantic automatically converts types!
2species = Species(id="1", name="Lion", population="120", endangered="yes")
3
4print(type(species.id)) # <class 'int'> (conversion str→int)
5print(type(species.population)) # <class 'int'>
6print(species.endangered) # True (conversion "yes"→True)1try:
2 # Invalid data
3 species = Species(id="abc", name="Lion", population=-50)
4except ValidationError as e:
5 print(e.json()) # Detailed validation errors1from pydantic import BaseModel, Field
2
3class Species(BaseModel):
4 id: int = Field(..., gt=0, description="Unique species ID")
5 name: str = Field(..., min_length=2, max_length=100)
6 scientific_name: str = Field(..., pattern=r'^[A-Z][a-z]+ [a-z]+$') # Regex
7 population: int = Field(..., ge=0, le=1_000_000) # >= 0, <= 1M
8 habitat: str = Field(default="unknown")
9
10# Validation works!
11lion = Species(
12 id=1,
13 name="Lion",
14 scientific_name="Panthera leo", # Must match the regex
15 population=120
16)Field validators:
gt, ge - greater than, greater or equallt, le - less than, less or equalmin_length, max_length - string lengthpattern - regex validationdescription - description for documentation1from pydantic import BaseModel, field_validator
2
3class Species(BaseModel):
4 name: str
5 population: int
6
7 @field_validator('name')
8 @classmethod
9 def name_must_be_capitalized(cls, v):
10 if not v[0].isupper():
11 raise ValueError('Name must start with an uppercase letter')
12 return v
13
14 @field_validator('population')
15 @classmethod
16 def population_realistic(cls, v):
17 if v > 1_000_000:
18 raise ValueError('Population exceeds realistic range')
19 return v
20
21# Validation works
22lion = Species(name="Lion", population=120) # OK
23lion = Species(name="lion", population=120) # ValueError!1from fastapi import FastAPI, HTTPException
2from pydantic import BaseModel, Field, field_validator
3from typing import Literal
4from datetime import datetime
5
6app = FastAPI()
7
8class SpeciesBase(BaseModel):
9 name: str = Field(..., min_length=2, max_length=100)
10 scientific_name: str = Field(..., pattern=r'^[A-Z][a-z]+ [a-z]+$')
11 population: int = Field(..., ge=0, le=1_000_000)
12 habitat: Literal["savanna", "forest", "desert", "wetland"]
13
14 @field_validator('scientific_name')
15 @classmethod
16 def validate_scientific_name(cls, v):
17 parts = v.split()
18 if len(parts) != 2:
19 raise ValueError('Scientific name must follow the format: Genus species')
20 return v
21
22class SpeciesCreate(SpeciesBase):
23 pass
24
25class Species(SpeciesBase):
26 id: int
27 created_at: datetime = Field(default_factory=datetime.now)
28
29 class Config:
30 from_attributes = True
31
32@app.post("/species", response_model=Species)
33async def create_species(species: SpeciesCreate):
34 # Pydantic automatically validates the data!
35 new_species = Species(id=1, **species.dict())
36 return new_speciesNext lesson: Async databases with SQLAlchemy! 🗄️⚡