Back-end

Czym jest Pydantic?

Pydantic to biblioteka dla języka Python, która pozwala na szybkie i łatwe tworzenie modeli danych z walidacją danych. Pydantic jest oparty na popularnej bibliotece Python - dataclasses i pozwala na definiowanie modeli danych jako klasy Python,

30 cze 2022

Jednym ze sposobów przechowywania zorganizowanych danych w Pythonie są klasy. Można użyć normalnej klasy z metodą __init__, można też tworzyć modele za pomocą wbudowanych modułów Pythona, takich jak dataclasses. Jednak jedną z bardziej rozbudowanych i wygodniejszych opcji jest biblioteka Pydantic. Umożliwia ona modelowanie, walidację i modyfikowanie danych w bardzo wygodny sposób. Spójrzmy na praktyczny przykład - załóżmy, że chcemy stworzyć zwykłą to-do listę. Będziemy potrzebować modelu ListItem i modelu samej listy, nazwijmy go ToDoList. ListItem powinien mieć treść i flagę mówiącą, czy task jest skończony, czy nie. ToDoList powinna mieć nazwę i listę obiektów klasy ListItem jako membera. W vanilla Pythonie wygląda to tak:

 

class ListItem:

    def __init__(self, content: str, done: bool = False):
        self.content = content
        self.done = done
   
        
class ToDoList:
    
    def __init__(self, name: str, items: typing.List[ListItem]):
        self.name = name
        self.items = items

 

Problem pojawia się już na samym początku, mianowicie tu:

list_item1 = ListItem(123, False)

 

Jak możemy zabezpieczyć naszą klasę przed złym typem atrybutu, który może być zagrożeniem przy zapisie danych do bazy lub wprowadzaniu danych od strony użytkownika?

 

Mamy taką opcję:

 

def __init__(self, content: str, done: bool = False):
        if not isinstance(content, str):
            raise Exception("Wrong type of content")
            
        self.content = content
        self.done = done

 

Z naszego kodu w tym momencie zaczyna robić się niezłe spaghetti. Zabezpieczenie w ten sposób każdej klasy będzie niepraktyczne, pracochłonne i podatne na błędy. Jest jeszcze jeden problem:

 

print(list_item1)  # <__main__.ListItem object at 0x7f641ca7d4c0>

 

Nie mamy szybkiego dostępu do zawartości naszej klasy w razie potrzeby sprawdzenia jej printem podczas modyfikacji lub “testowania” naszego kodu. Zawsze możemy dodać metodę __repr__, która zmieni reprezentację obiektu, jednak są to kolejne linijki kodu do napisania. Te problemy rozwiązuje Pydantic. Zobaczmy jak wygląda nasz kod po konwersji na Pydantic:

 

from pydantic import BaseModel
import typing


class ListItem(BaseModel):
	content: str
	done: bool = False


class ToDoList(BaseModel):
	name: str
	items: typing.List[ListItem]

 

A teraz spójrzmy jak zachowuje się nasza klasa w kwestii walidacji i reprezentacji:

 

list_item1 = ListItem(content=123, done=True)
print(list_item)  # ListItem(content='123', done=True)

 

Pydantic przekonwertuje typ atrybutu, jeśli jest to możliwe, lub wyrzuci nam wyjątek, jeśli nie ma możliwości konwersji. Dodatkowo od razu otrzymujemy czytelną i pełną informacji reprezentację instancji. Dostajemy także wygodny sposób tworzenia słownika z danych naszej instancji poprzez metodę .dict(). A co jeśli chcemy dokonać bardziej złożonej walidacji? Załóżmy, że mamy klasę reprezentującą człowieka, która przechowuje numer PESEL. Dla uproszczenia przyjmijmy, że mamy funkcję sprawdzającą liczbę kontrolną numeru PESEL, zwracającą True lub False:

 

from pydantic import BaseModel, validator


class Human(BaseModel):
	pesel: int

	@validator('pesel')
	def validate_pesel(cls, v):
		if is_control_number_valid(v) is False:
			raise ValueError('Given PESEL number is invalid')
		return v

 

W argumencie  v  dostajemy wartość numeru PESEL już po konwersji typów (tworzenie modeli zachodzi od dołu do góry struktury danych), w razie nieprawidłowości wyrzucamy ValueError, który zostaje przekonwertowany przez Pydantic na pydantic.ValidationError. Możemy w tym miejscu sprawdzić długość stringa, lub znak liczby całkowitej. Można także modyfikować opcje walidacji, takie jak walidacja przy przypisaniu wartości czy zastosowanie walidacji dla każdego elementu, jeśli pole jest kolekcją. Dostęp do pozostałych wartości przekazanych do instancji, możemy otrzymać poprzez argument values funkcji walidującej.

 

Warto również wspomnieć, że Pydantic jest natywnie wspierany przez framework webowy FastAPI, co pozwala na łatwą walidację wartości przesyłanych do endpointów typu POST i PUT, oraz jasne i sztywne określenie struktury danych zwracanych przez endpointy typu GET. 
Podsumowując, Pydantic jest świetną biblioteką do modelowania klas, ułatwiającą pisanie czystego, prostego i przede wszystkim działającego kodu, która oferuje masę niezwykle przydatnych funkcjonalności.

 

FAQ

FAQ – najczęstsze pytania o Pydantic

  • Pydantic to biblioteka Pythona służąca do modelowania, walidacji i modyfikowania danych. Pozwala definiować klasy danych na podstawie BaseModel, w których każde pole ma określony typ. Pydantic automatycznie waliduje wartości przekazywane do instancji – konwertuje typy, jeśli to możliwe, lub rzuca pydantic.ValidationError, gdy konwersja jest niemożliwa. Eliminuje potrzebę ręcznego pisania kodu walidującego w __init__.

  • W zwykłej klasie z __init__ trzeba ręcznie sprawdzać typy każdego atrybutu (`if not isinstance(content, str): raise Exception`), co prowadzi do spaghetti i jest pracochłonne. Domyślne repr (`<__main__.ListItem object at 0x7f...>`) jest nieczytelne. Pydantic rozwiązuje oba problemy – waliduje typy automatycznie i dostarcza czytelną reprezentację instancji, np. `ListItem(content='123', done=True)`.

  • Gdy do pola Pydantic przekazana jest wartość niezgodna z deklarowanym typem, biblioteka próbuje ją skonwertować. Na przykład `ListItem(content=123, done=True)` zostanie zapisane jako `ListItem(content='123', done=True)` – int automatycznie zamienia się w str. Jeśli konwersja jest niemożliwa, Pydantic zgłasza wyjątek. Dzięki temu zabezpieczenie przed niewłaściwymi typami danych nie wymaga ręcznego kodu w klasie.

  • Do bardziej złożonej walidacji służy dekorator @validator. Przykład: dla klasy `Human(BaseModel)` z polem `pesel: int` można dodać metodę z `@validator('pesel')`, która sprawdza liczbę kontrolną i rzuca ValueError, jeśli numer jest nieprawidłowy. Pydantic konwertuje ValueError na pydantic.ValidationError. Można też uzyskać dostęp do pozostałych wartości instancji przez argument `values` funkcji walidującej.

  • Pydantic jest natywnie wspierany przez framework webowy FastAPI. Pozwala to na łatwą walidację wartości przesyłanych do endpointów typu POST i PUT – jeśli żądanie nie pasuje do modelu, FastAPI automatycznie zwraca błąd walidacji. Pydantic umożliwia też jasne i sztywne określenie struktury danych zwracanych przez endpointy typu GET, dzięki czemu API jest dobrze udokumentowane i przewidywalne.

  • Pydantic dostarcza wygodną metodę .dict(), która zwraca słownik z danych instancji modelu. Pozwala to łatwo serializować obiekty do formatów takich jak JSON, zapisywać do bazy danych lub przesyłać przez API. Można też modyfikować opcje walidacji, takie jak walidacja przy przypisaniu wartości (validate_assignment) czy stosowanie walidacji dla każdego elementu, jeśli pole jest kolekcją.

Blog

Powiązane artykuły

Czytaj więcej
Back-end

GraalVM: Rewolucja w świecie wirtualnych maszyn

GraalVM wprowadza przełom w świecie wirtualnych maszyn, oferując wyjątkową uniwersalność i wydajność. Zaprojektowany z myślą o współczesnych wymaganiach programistycznych, umożliwia uruchamianie kodu napisanego w wielu językach, w tym Java, JavaScript, Python, i innych, na jednej platformie.

Tomasz Kozon
06 lut 2024
Back-end

GRPC: kiedy i dlaczego warto używać?

gRPC to nowoczesny, otwartoźródłowy framework zdalnego wywoływania procedur, który zdobywa coraz szersze uznanie wśród deweloperów. Ten artykuł wyjaśni kluczowe przewagi gRPC, omówi sytuacje, w której jego zastosowanie może okazać się szczególnie korzystne i przedstawi istotne aspekty pracy z tą technologią.

Tomasz Kozon
14 gru 2023
Back-end

Headless CMS - lista popularnych technologii

W ostatnim czasie coraz więcej firm decyduje się na wykorzystanie technologii Headless CMS. Jest to spowodowane coraz większym zapotrzebowaniem na elastyczność i możliwość tworzenia aplikacji internetowych, które będą dostosowane do indywidualnych potrzeb użytkownika.

Tomasz Kozon
05 lip 2022
Back-end

Czym jest HTTP 301 i kiedy warto go użyć?

HTTP 301 to status kodu, który informuje przeglądarkę oraz wyszukiwarki, że zasób, którego dotyczy żądanie, został przeniesiony na stałe do nowego adresu URL. Oznacza to, że zasób już nie jest dostępny pod starym adresem URL, a wszystkie przyszłe żądania powinny kierować do nowego adresu.

Tomasz Kozon
19 paź 2022
Back-end

Co to jest Joomla i jakie daje możliwości?

Joomla to popularny system zarządzania treścią (CMS), który pozwala na łatwe tworzenie i zarządzanie witrynami internetowymi. Jest to otwarty i darmowy system, który jest dostępny dla każdego, kto chce stworzyć profesjonalną stronę internetową.

Tomasz Kozon
15 lip 2022
Back-end

Assembler - niskopoziomowy język programowania

Assembler to niskopoziomowy język programowania, który umożliwia bezpośrednie manipulowanie sprzętem komputera. Choć coraz rzadziej używany, wciąż stanowi cenną umiejętność dla programistów zajmujących się optymalizacją lub tworzeniem oprogramowania wbudowanego.

Tomasz Kozon
20 maj 2023