Witaj, @name! Darwin tutaj z Pydantic - najpotężniejszym systemem walidacji danych w Pythonie! 📊✅
Pydantic to core FastAPI - każdy request/response przechodzi przez walidację Pydantic. W wersji 2.0 został przepisany w Rust i jest 17× szybszy! ⚡🦀
Analogia Safari: Pydantic to jak system kontroli jakości obserwacji - sprawdza, czy każda obserwacja ma poprawne dane (gatunek istnieje, populacja to liczba, data jest prawidłowa). Jeśli coś jest nie tak, od razu zgłasza błąd! 🔍✅
1from pydantic import BaseModel
2
3class Species(BaseModel):
4 id: int
5 name: str
6 population: int
7 endangered: bool = False # Domyślna wartość
8
9# Tworzenie instancji
10lion = Species(id=1, name="Lew", population=120, endangered=True)
11
12print(lion.name) # "Lew"
13print(lion.dict()) # {'id': 1, 'name': 'Lew', 'population': 120, 'endangered': True}
14print(lion.json()) # JSON string1# Pydantic automatycznie konwertuje typy!
2species = Species(id="1", name="Lew", population="120", endangered="yes")
3
4print(type(species.id)) # <class 'int'> (konwersja str→int)
5print(type(species.population)) # <class 'int'>
6print(species.endangered) # True (konwersja "yes"→True)1try:
2 # Błędne dane
3 species = Species(id="abc", name="Lew", population=-50)
4except ValidationError as e:
5 print(e.json()) # Szczegółowe błędy walidacji1from 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# Walidacja działa!
11lion = Species(
12 id=1,
13 name="Lew",
14 scientific_name="Panthera leo", # Musi pasować do regex
15 population=120
16)Field validators:
gt, ge - greater than, greater or equallt, le - less than, less or equalmin_length, max_length - długość stringpattern - regex validationdescription - opis dla dokumentacji1from 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('Nazwa musi zaczynać się wielką literą')
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('Populacja przekracza realistyczny zakres')
19 return v
20
21# Walidacja działa
22lion = Species(name="Lew", population=120) # OK
23lion = Species(name="lew", 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('Nazwa naukowa musi mieć 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 automatycznie waliduje dane!
35 new_species = Species(id=1, **species.dict())
36 return new_speciesNastępna lekcja: Async databases z SQLAlchemy! 🗄️⚡