Utilizziamo i cookie per migliorare la tua esperienza sul sito
CodeWorlds

Pydantic - walidacja danych z Rust

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! 🔍✅

Podstawy Pydantic

BaseModel - klasa bazowa

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 string

Automatyczna konwersja typów

1# 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)

Walidacja błędów

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 walidacji

Field - zaawansowana walidacja

1from 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 equal
  • lt
    ,
    le
    - less than, less or equal
  • min_length
    ,
    max_length
    - długość string
  • pattern
    - regex validation
  • description
    - opis dla dokumentacji

Custom validators

1from 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!

Safari API z Pydantic

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_species

Podsumowanie

  • ✅ BaseModel - klasa bazowa
  • ✅ Automatyczna konwersja typów
  • ✅ Field validators (gt, ge, pattern, etc.)
  • ✅ Custom validators (@field_validator)
  • ✅ Safari API z Pydantic

Następna lekcja: Async databases z SQLAlchemy! 🗄️⚡

Vai a CodeWorlds