Wróć do katalogu
Season 9 20 Odcinki 1h 16m 2026

Pydantic: Data Validation

Wydanie v2.12 — 2026. Dogłębne spojrzenie na Pydantic v2.12, najczęściej używaną bibliotekę do walidacji danych w języku Python, od podstawowego użycia po zaawansowane funkcje, takie jak custom core schemas i obserwowalność za pomocą Logfire.

Walidacja danych Python Core
Pydantic: Data Validation
Teraz odtwarzane
Click play to start
0:00
0:00
1
Filozofia Pydantic: Type Hints jako walidacja
Ten odcinek przedstawia główne założenia Pydantic. Dowiesz się, jak type hints w Pythonie mogą być używane do wymuszania schematów i jak rdzeń napisany w Rust napędza ogromny wzrost wydajności.
3m 29s
2
Anatomia BaseModel
Zanurz się w BaseModel, podstawową abstrakcję Pydantic. Dowiesz się, jak tworzenie instancji waliduje dane, jak dane są rzutowane i jak ujawniane są błędy walidacji.
4m 11s
3
Ograniczenia pól i wzorzec Annotated
Dowiedz się, jak wymuszać limity wykraczające poza podstawowe typy. Odkryjesz, jak używać funkcji Field i konstrukcji typowania Annotated, aby dodawać ograniczenia, takie jak wartości minimalne i maksymalne długości.
4m 26s
4
Aliasy pól do walidacji i serializacji
Rozwiąż konflikt konwencji nazewnictwa między zewnętrznymi API a wewnętrznym kodem Pythona. Dowiesz się, jak oddzielić nazwy atrybutów w Pythonie od kluczy JSON za pomocą aliasów walidacji i serializacji.
4m 01s
5
Rzutowanie danych a Strict Mode
Przejmij kontrolę nad skłonnością Pydantic do rzutowania danych. Dowiesz się, jak wymusić dokładne dopasowanie typów, włączając Strict Mode na poziomie pola lub modelu.
4m 00s
6
Obserwowalność w świecie rzeczywistym z Logfire
Wprowadź przejrzystość do swoich potoków danych. Dowiesz się, jak zintegrować Pydantic z Logfire, aby monitorować udane i nieudane walidacje w czasie rzeczywistym.
3m 55s
7
Walidacja dowolnych typów za pomocą TypeAdapter
Dowiedz się, jak walidować samodzielne typy proste i listy bez tworzenia BaseModel. Odkryjesz, jak TypeAdapter zamienia dowolny typ w Pythonie w pełnoprawny cel walidacji.
4m 09s
8
Typy Union i inteligentna walidacja
Zrozum złożoność walidacji typu Union. Dowiesz się, jak Smart Mode w Pydantic ocenia dokładność i prawidłowe pola, aby wybrać najlepsze dopasowanie.
3m 37s
9
Potężne narzędzie: Discriminated Unions
Zwiększ wydajność swojej walidacji. Dowiesz się, jak używać Discriminated (Tagged) Unions, aby dokładnie powiedzieć Pydantic, który schemat zastosować na podstawie określonego pola.
3m 55s
10
Przetwarzanie wstępne z Before Validators i Wrap Validators
Poradź sobie z nieuporządkowanymi danymi wejściowymi, zanim trafią do twojego schematu. Dowiesz się, jak używać walidatorów pól Before i Wrap, aby wyczyścić surowe dane wejściowe, zanim Pydantic je oceni.
3m 53s
11
Przetwarzanie końcowe z After Validators i Plain Validators
Wymuszaj surowe reguły logiki biznesowej. Dowiesz się, jak używać After Validators do weryfikacji już sparsowanych danych oraz Plain Validators, aby całkowicie pominąć standardową walidację Pydantic.
3m 37s
12
Hooki walidacyjne na poziomie modelu
Waliduj interakcje między wieloma polami. Dowiesz się, jak używać dekoratora model_validator, aby wymuszać reguły zależne od całego payloadu.
3m 48s
13
Serializacja: Bezpieczne zrzucanie danych
Kontroluj, jak twoje dane opuszczają system. Poznasz różnice między zrzucaniem do Python dicts a ciągami JSON oraz dowiesz się, jak wykluczać nieustawione lub domyślne pola.
4m 08s
14
Dostosowywanie logiki serializacji
Zmień sposób reprezentacji swoich typów na wyjściu. Dowiesz się, jak pisać niestandardowe serializatory Field i Model, aby modyfikować dane podczas fazy zrzucania.
2m 48s
15
Generowanie JSON Schema z modeli
Zamień swoje modele w samodokumentujące się kontrakty API. Dowiesz się, jak generować zgodne z OpenAPI JSON Schemas i wstrzykiwać przykłady bezpośrednio do schematu.
3m 59s
16
RootModel: Gdy twój payload nie jest słownikiem
Elegancko obsługuj niestandardowe payloady JSON. Odkryjesz, jak RootModel pozwala parsować tablice i typy proste na poziomie głównym, zachowując przy tym możliwości BaseModel.
3m 36s
17
Standardowe Dataclasses a Pydantic Dataclasses
Wprowadź walidację do swoich natywnych klas Pythona. Dowiesz się, kiedy używać dekoratora dataclass z Pydantic, aby zmodernizować starsze bazy kodu bez przepisywania wszystkiego.
3m 58s
18
Dostrajanie konfiguracji modelu
Kontroluj rygorystyczność całego modelu. Dowiesz się, jak używać ConfigDict, aby zabronić dodatkowych atrybutów, zamrażać instancje i walidować przypisania.
3m 35s
19
Konfiguracja aplikacji z Pydantic Settings
Zarządzaj zmiennymi środowiskowymi jak profesjonalista. Dowiesz się, jak pakiet pydantic-settings automatyzuje parsowanie sekretów, plików dot-env i prefiksów.
4m 00s
20
Pod maską: Custom Core Schemas
To już ostatni odcinek serii! Przejmij całkowitą kontrolę nad silnikiem walidacji. Dowiesz się, jak napisać metodę __get_pydantic_core_schema__, aby nauczyć rdzeń w Rust, jak obsługiwać całkowicie obce obiekty Pythona.
3m 41s

Odcinki

1

Filozofia Pydantic: Type Hints jako walidacja

3m 29s

Ten odcinek przedstawia główne założenia Pydantic. Dowiesz się, jak type hints w Pythonie mogą być używane do wymuszania schematów i jak rdzeń napisany w Rust napędza ogromny wzrost wydajności.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 1 z 20. Większość bibliotek do walidacji danych zmusza cię do nauki zupełnie nowego języka specyficznego dla danej dziedziny, tylko po to, żeby zdefiniować schemat. Ale co, jeśli wbudowana składnia Pythona w zupełności by wystarczyła do egzekwowania twoich reguł? Filozofia Pydantic: Type hints jako walidacja, rozwiązuje dokładnie ten problem. Zanim przyjrzymy się, jak to działa, musimy wyjaśnić pewne powszechne nieporozumienie. Pydantic nie jest statycznym type checkerem, takim jak mypy. Mypy analizuje twój kod źródłowy przed jego uruchomieniem, żeby wychwycić błędy logiczne. Pydantic działa w runtimie. Bierze niezaufane dane ze świata zewnętrznego, takie jak payload JSON z requestu API, i wymusza ich zgodność z typami, które zdefiniowałeś, dokładnie w trakcie działania twojego programu. Główną filozofią jest tutaj prostota. Definiujesz model danych za pomocą standardowych adnotacji typów w Pythonie. Tworzysz klasę reprezentującą użytkownika i określasz, że user ID to integer, a data rejestracji to obiekt datetime. To cały twój schemat. Nie piszesz customowych funkcji walidacyjnych ani nie importujesz dedykowanych typów pól. Kiedy z formularza na stronie przychodzi nieuporządkowany słownik, po prostu przekazujesz go do swojej klasy. Pydantic go przechwytuje i gwarantuje, że wynikowy obiekt ściśle trzyma się tych typów. I tu jest kluczowa sprawa. Pydantic to w gruncie rzeczy biblioteka do parsowania, a nie tylko bramka do ścisłej walidacji. Jeśli użytkownik wyśle formularz, w którym user ID to string czterdzieści dwa, Pydantic rozpozna, że twój model oczekuje integera. Automatycznie konwertuje ten string na natywnego pythonowego integera. Zanim rzuci błędem, stara się dopasować dane do twojego schematu. To załatwia żmudną konwersję danych, dzięki czemu nie musisz pisać ręcznej logiki parsowania dla każdego pola wejściowego. Walidacja i konwersja każdego pojedynczego elementu przychodzących danych w runtimie brzmi jak coś z natury powolnego, szczególnie w Pythonie. Żeby to rozwiązać, logika wykonawcza tak naprawdę nie działa w Pythonie. Pydantic deleguje czarną robotę do dedykowanego silnika napisanego w całości w Ruście. Taki design daje ci świetny developer experience pisania w czystym Pythonie, połączony z surową prędkością wykonywania skompilowanego kodu systemowego. Wyobraź sobie background task, który parsuje ogromny plik JSON, gdzie każdy rekord zawiera adres internetowy. Jeśli napiszesz kod w czystym Pythonie, żeby w pętli przejść przez tysiące słowników, wyciągnąć każdy string, załadować bibliotekę wyrażeń regularnych i zweryfikować, czy każdy string to poprawny URL, twój proces będzie się wlókł. Pydantic radzi sobie z tym bezproblemowo. Po prostu dodajesz adnotację do pola adresu jako typ URL i karmisz swój model surowym JSON-em. Silnik w Ruście błyskawicznie przelatuje przez tekst, parsując i walidując formaty z prędkością, której natywny Python nie jest w stanie dorównać. Prawdziwą siłą tego podejścia jest to, że autocomplete w twoim edytorze, twoje narzędzia do analizy statycznej i walidacja w runtimie korzystają z dokładnie tego samego źródła prawdy, czyli twoich standardowych type hintów. Jeśli uważasz te odcinki za przydatne i chcesz wesprzeć program, możesz wyszukać DevStoriesEU na Patreonie. To wszystko na dzisiaj. Dzięki za wysłuchanie i twórz dalej!
2

Anatomia BaseModel

4m 11s

Zanurz się w BaseModel, podstawową abstrakcję Pydantic. Dowiesz się, jak tworzenie instancji waliduje dane, jak dane są rzutowane i jak ujawniane są błędy walidacji.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 2 z 20. Często mówimy o walidacji danych, ale jeśli przyjrzysz się bliżej Pydantic, jego głównym celem jest tak naprawdę coercion. Gwarantuje on strukturę twojego outputu, a nie inputu. Anatomia BaseModel to coś, co umożliwia to rozróżnienie. Klasa BaseModel to fundament Pydantic. Aby zdefiniować schemat, tworzysz standardową klasę w Pythonie i dziedziczysz po BaseModel. Kiedy to zrobisz, Pydantic przekształca twoją klasę w ścisły kontener danych. Kształt swoich danych definiujesz za pomocą standardowych type hints z Pythona. Nie potrzebujesz żadnych dedykowanych funkcji, żeby zadeklarować stringa czy liczbę. Po prostu piszesz nazwę atrybutu, dwukropek i oczekiwany typ z Pythona. Weźmy na przykład model User. Wewnątrz klasy definiujesz jedno pole o nazwie id i typujesz je jako integer. Możesz też dodać pole name otypowane jako string. I to już cała definicja. A oto kluczowa sprawa. Prawdziwa praca dzieje się w momencie, gdy tworzysz instancję modelu. Tworzysz instancję, przekazując swoje dane jako keyword arguments, które pasują do zdefiniowanych przez ciebie nazw pól. Kiedy to robisz, Pydantic przechwytuje dane, zanim obiekt zostanie w pełni zainicjalizowany. Porównuje przychodzące wartości z twoimi type hints. I właśnie tutaj wkracza coercion. Jeśli do pola id przekażesz integera jeden-dwa-trzy, Pydantic zaakceptuje go natychmiast. Ale załóżmy, że odbierasz dane z web requestu albo pliku tekstowego i przekazujesz stringa "123" do dokładnie tego samego pola. Pydantic nie rzuca od razu błędem. Rozpoznaje, że docelowy typ to integer i próbuje przekonwertować tego stringa. Ponieważ te znaki można bezpiecznie zrzutować na liczbę, Pydantic wykonuje konwersję po cichu. Obiekt zostaje utworzony, a pole id przechowuje prawdziwego pythonowego integera, a nie stringa. To zachowanie dowodzi, że Pydantic jest w gruncie rzeczy biblioteką do parsowania. Transformuje przychodzące dane tak, aby pasowały do ścisłego schematu, który zdefiniowałeś. Oczywiście, ta konwersja ma swoje logiczne granice. Jeśli utworzysz instancję modelu User i przekażesz stringa "not an int" do pola id, Pydantic spróbuje wykonać konwersję i poniesie porażkę. Kiedy coercion jest niemożliwe, Pydantic rzuca ValidationError. Ten błąd natychmiast zatrzymuje wykonywanie kodu. Kluczowym szczegółem dotyczącym ValidationError jest to, że Pydantic sprawdza wszystkie pola przed jego rzuceniem. Jeśli twój model ma wiele pól z nieprawidłowymi danymi, wyjątek będzie zawierał szczegóły wszystkich błędów, zamiast zatrzymywać się na pierwszej pomyłce. Błąd wskazuje dokładne pola, które spowodowały problem, konkretne przekazane wartości i powody, dla których nie udało się ich sparsować. Kiedy twoje dane pomyślnie przejdą przez proces tworzenia instancji, masz gwarancję, że wynikowy obiekt będzie pasował do twoich type hints. Do danych dostajesz się dokładnie tak samo, jak w każdym standardowym obiekcie w Pythonie, używając dot notation. Jeśli przypisałeś instancję do zmiennej o nazwie user, po prostu wpisujesz user dot id, żeby pobrać integera. Nie są tu wymagane żadne metody typu getter czy setter. Wchodzisz w interakcję z czystym, silnie typowanym obiektem. Prawdziwa wartość dziedziczenia po BaseModel polega nie tylko na tym, że odrzuca on złe inputy, ale też na tym, że bezpiecznie normalizuje nieprzewidywalne dane zewnętrzne do wysoce przewidywalnego stanu wewnętrznego. Dzięki za wysłuchanie. Trzymajcie się wszyscy.
3

Ograniczenia pól i wzorzec Annotated

4m 26s

Dowiedz się, jak wymuszać limity wykraczające poza podstawowe typy. Odkryjesz, jak używać funkcji Field i konstrukcji typowania Annotated, aby dodawać ograniczenia, takie jak wartości minimalne i maksymalne długości.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 3 z 20. Standardowe type hinty mówią ci, że pole to integer, ale nie powiedzą ci, że musi być większe od zera. Kiedy ujemny wiek albo username na dziesięć tysięcy znaków prześlizgnie się przez granice twojej aplikacji, podstawowy type checking to za mało, żeby ochronić twój backend. Żeby wymusić ścisłe granice na twoich danych, potrzebujesz Field Constraints i wzorca Annotated. W Pydantic constraints pozwalają ci ograniczyć dozwolone wartości dla konkretnego typu. Zamiast pisać customowe funkcje walidujące dla każdej drobnej reguły, możesz zdefiniować matematyczne lub strukturalne granice bezpośrednio na polu. Dla typów numerycznych możesz wymusić granice greater than lub less than, używając parametrów takich jak g-t i l-t. Dla stringów możesz ograniczyć rozmiar inputu, używając max length i min length. Żeby zastosować te reguły, Pydantic dostarcza funkcję narzędziową o nazwie Field. Tradycyjnie developerzy aplikowali te constraints, przypisując wywołanie funkcji Field jako domyślną wartość atrybutu modelu. Na przykład, deklarowałbyś atrybut age, dawał type hint jako integer i ustawiał go na Field, przekazując g-t równe zero. Ta struktura działa, ale wprowadza pewne tarcie. Jeśli potrzebujesz dodatniego integera w piętnastu różnych modelach, piszesz dokładnie to samo przypisanie Field piętnaście razy. Co gorsza, ponieważ funkcja Field zajmuje slot przypisania domyślnej wartości w modelu, komplikuje to sprawę, kiedy faktycznie chcesz przypisać prawdziwy domyślny integer do tego atrybutu. Oto kluczowa sprawa. Wcale nie musisz wiązać swoich reguł walidacji z przypisaniem atrybutu. Możesz je wbudować bezpośrednio w samą definicję typu, używając typing dot Annotated z Pythona. Annotated to funkcja biblioteki standardowej, która pozwala ci dołączyć dowolne metadane do bazowego type hinta. Pydantic jest specjalnie zaprojektowany, żeby zajrzeć do środka typu Annotated, znaleźć wszystkie funkcje Field, które podałeś, i automatycznie wyciągnąć ich reguły walidacji. Kiedy używasz Annotated, przekazujesz mu dwie różne informacje. Po pierwsze, podajesz bazowy typ Pythona, jak integer albo string. Po drugie, podajesz metadane, którymi w naszym przypadku jest funkcja Field z Pydantica, zawierająca twoje constraints. Zbudujmy reużywalny typ dla wieku, żeby zobaczyć, jak to działa. Definiujesz w swoim kodzie nową zmienną o nazwie PositiveInt. Przypisujesz ją do Annotated. Wewnątrz Annotated przekazujesz integer jako typ bazowy, potem przecinek, a następnie funkcję Field z g-t równym zero. Właśnie stworzyłeś customowe, reużywalne type constraint. Teraz, za każdym razem, gdy definiujesz model usera albo pracownika, po prostu dajesz type hint dla pola age jako PositiveInt. Nie musisz wywoływać funkcji Field na atrybucie modelu. To podejście oddziela twoje definicje typów od struktur modelu. Twoje modele pozostają niesamowicie czyste, czyta się je jak standardowe klasy Pythona, bez żadnego bałaganu. Jeśli twoja logika biznesowa zmieni się później i nagle będziesz potrzebować, żeby pole age było większe niż osiemnaście zamiast zera, aktualizujesz definicję PositiveInt w dokładnie jednym miejscu. To zaktualizowane constraint kaskaduje natychmiast do każdego modelu, który go używa. Co więcej, ponieważ Annotated to natywny feature Pythona, statyczne type checkery doskonale rozumieją, że twój customowy PositiveInt jest ostatecznie ewaluowany jako standardowy integer. Oddzielając metadane walidacji od slotu domyślnej wartości, wzorzec Annotated przekształca field constraints z powtarzalnego boilerplate'u we współdzieloną bibliotekę ścisłych, reużywalnych typów domenowych. Dzięki za spędzenie ze mną tych kilku minut. Do usłyszenia następnym razem, trzymaj się.
4

Aliasy pól do walidacji i serializacji

4m 01s

Rozwiąż konflikt konwencji nazewnictwa między zewnętrznymi API a wewnętrznym kodem Pythona. Dowiesz się, jak oddzielić nazwy atrybutów w Pythonie od kluczy JSON za pomocą aliasów walidacji i serializacji.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 4 z 20. Czy kiedykolwiek musiałeś nazwać zmienną w Pythonie używając camel case, tylko po to, żeby sparsować payload z zewnętrznego API? Wiesz, że to łamie standardowe konwencje nazewnictwa w Pythonie, ale przychodzący JSON dyktuje klucz. Rozwiązaniem tego problemu są aliasy pól do walidacji i serializacji. Kiedy pobierasz dane, klucze w tym payloadzie często nie pasują do tego, jak chcesz ustrukturyzować swój kod w Pythonie. Jeśli zewnętrzne API wysyła profil użytkownika z kluczem user wielkie N name, chcesz to zmapować na standardową zmienną w snake case o nazwie user underscore name. Pydantic obsługuje tę warstwę translacji za pomocą funkcji Field, a konkretnie przez jej argumenty alias. Najprostszym podejściem jest bazowy argument alias. Deklarując atrybut modelu, przypisujesz mu Field i ustawiasz parametr alias na string oczekiwany ze świata zewnętrznego. Jeśli ustawisz alias na wersję camel case, Pydantic użyje dokładnie tego stringa zarówno do odczytu, jak i zapisu. Podczas walidacji przychodzących danych, szuka klucza w camel case. Kiedy później serializujesz model, żeby zrobić dump z powrotem do JSONa, zapisuje klucz w camel case. Twój wewnętrzny kod w Pythonie operuje wyłącznie na atrybucie w snake case, całkowicie odizolowany od zewnętrznej konwencji nazewnictwa. To załatwia sprawę danych symetrycznych, gdzie format wejściowy i wyjściowy są identyczne. Drugą kwestią są dane asymetryczne. Co się dzieje, gdy konsumujesz dane z systemu legacy używającego jednej konwencji nazewnictwa, ale musisz je zaserwować nowemu klientowi w innej? W tym miejscu rozdzielasz logikę, używając validation alias i serialization alias. Są to oddzielne argumenty, które przekazujesz do funkcji Field. Validation alias ściśle określa, czego Pydantic szuka podczas tworzenia modelu. Jeśli podasz validation alias, Pydantic użyje go do wyciągnięcia wartości z przychodzącego payloadu, nadpisując każdy bazowy alias, który mogłeś ustawić. Z kolei serialization alias kontroluje tylko fazę wyjściową. Kiedy wywołujesz metodę, żeby zrobić dump modelu do dicta lub stringa JSON, Pydantic używa serialization alias jako klucza wyjściowego. Oto kluczowa sprawa. Możesz zdefiniować jedno pole z trzema różnymi tożsamościami. Validation alias przechwytuje chaotyczny string wejściowy z API legacy. Atrybut w Pythonie przechowuje czystą zmienną w snake case, której używasz w swojej logice biznesowej. Na koniec, serialization alias definiuje dopracowany, ustandaryzowany klucz, który jest wysyłany do twojego frontendu. Czasami problemem nie jest sztywna konwencja nazewnictwa, ale jej niespójność. Możesz otrzymywać payloady, w których identyfikator użytkownika to czasami camel case, a czasami pojedyncze słowo bez spacji. Żeby sobie z tym poradzić, Pydantic udostępnia narzędzie o nazwie AliasChoices. Zamiast przekazywać pojedynczy string do validation alias, przekazujesz to narzędzie zawierające listę stringów. Podczas walidacji, Pydantic skanuje przychodzący payload w poszukiwaniu każdego stringa w podanej przez ciebie kolejności. W momencie, gdy znajdzie pasujący klucz, wyciąga wartość, przypisuje ją do twojego atrybutu w Pythonie i ignoruje resztę. Oddzielając sposób parsowania danych od sposobu ich eksportowania, aliasy uniezależniają wewnętrzny design twojego obiektu w Pythonie od arbitralnych ograniczeń nazewnictwa ze świata zewnętrznego. To wszystko w tym odcinku. Dzięki za wysłuchanie i twórz dalej!
5

Rzutowanie danych a Strict Mode

4m 00s

Przejmij kontrolę nad skłonnością Pydantic do rzutowania danych. Dowiesz się, jak wymusić dokładne dopasowanie typów, włączając Strict Mode na poziomie pola lub modelu.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 5 z 20. Zapał Pydantica do zamiany stringa "123" na integera to killer feature, dopóki po cichu nie ukryje błędu typu danych w twoim payloadzie JSON. Oczekujesz liczb, dostajesz stringi, a twoja aplikacja radośnie działa dalej, dopóki jakiś restrykcyjny system downstreamowy się nie wywali. Mechanizm, który kontroluje to zachowanie, to Data Coercion, a jego opanowanie wymaga zrozumienia Strict Mode. Domyślnie Pydantic działa w trybie, który dokumentacja nazywa lax mode. W tym trybie Pydantic działa jak data parser, a nie tylko type checker. Aktywnie próbuje zrobić coerce, czyli przekonwertować przychodzące dane na typ, który zadeklarowałeś. Jeśli zdefiniujesz pole jako integer, a wejściowy payload dostarczy stringa "123", Pydantic ewaluuje tego stringa, wyciąga z niego prawidłową liczbę i przekształca ją w prawdziwego integera. To zachowanie jest niesamowicie przydatne podczas przetwarzania inputu od użytkownika z formularzy webowych albo query parameters, gdzie każda przychodząca wartość jest z założenia stringiem. Jednak kiedy budujesz API typu machine-to-machine, cicha konwersja jest często niebezpieczna. Jeśli klient obiecuje wysłać integera, ale zamiast tego wysyła stringa, to łamie kontrakt API. Lax mode ukrywa to naruszenie. I tutaj wkracza strict mode. Strict mode wyłącza automatyczne type coercion. Kiedy go włączysz, Pydantic wymaga, żeby przychodzący typ danych dokładnie pasował do twojej type annotation. Przekaż stringa "123" do pola strict integer, a Pydantic natychmiast go odrzuci z błędem walidacji. Wymusza to na źródle danych przestrzeganie schematu. Masz dwa sposoby na zastosowanie strict mode: globalnie dla całego modelu, albo lokalnie na konkretnych polach. Żeby wymusić go globalnie, modyfikujesz konfigurację modelu. Ustawiając flagę konfiguracji strict na true, każde pojedyncze pole w tym modelu przestaje robić type coercion. Pole boolean przyjmie tylko wartość boolean true lub false, a nie stringa "true" czy integera jeden. Pole integer przyjmie tylko integery. I tu jest kluczowa sprawa. Globalny strict mode jest często zbyt sztywny dla prawdziwych aplikacji, gdzie dane przychodzą z różnych źródeł. Zazwyczaj chcesz zablokować kilka krytycznych identyfikatorów, zostawiając resztę modelu elastyczną. Żeby to osiągnąć, Pydantic pozwala na lokalny strict mode. Możesz wymusić strict mode na pojedynczym polu, używając specjalistycznych typów dostarczanych przez bibliotekę, takich jak StrictInt, StrictStr czy StrictBool. Jeśli zdefiniujesz pole user ID używając StrictInt, to konkretne pole odrzuci stringowe reprezentacje liczb, podczas gdy reszta twojego modelu będzie dalej działać w lax mode. Możesz to również osiągnąć, przekazując flagę strict bezpośrednio do funkcji definiującej pole dla dowolnego standardowego typu. Wyobraź sobie serwis przetwarzający payload JSON dla transakcji finansowej. Payload zawiera account ID. Jeśli zdefiniujesz go jako normalnego integera, payload dostarczający account ID jako stringa "123" przejdzie bez problemu. Pydantic poprawia typ danych w pamięci. Jeśli zaktualizujesz to pole, żeby używało StrictInt, dokładnie ten sam payload JSON nie przejdzie walidacji. Klient dostaje jawny błąd mówiący, że input musi być prawidłowym integerem, wyłapując naruszenie kontraktu na granicy systemu, zanim zanieczyści to twoją bazę danych. Strict mode zmienia Pydantica z pomocnego parsera, który czyści zabałaganione inputy, w sztywnego strażnika, który gwarantuje kontrakty danych. Dzięki za wysłuchanie. Trzymajcie się wszyscy.
6

Obserwowalność w świecie rzeczywistym z Logfire

3m 55s

Wprowadź przejrzystość do swoich potoków danych. Dowiesz się, jak zintegrować Pydantic z Logfire, aby monitorować udane i nieudane walidacje w czasie rzeczywistym.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 6 z 20. Kiedy skomplikowany payload nie przejdzie walidacji na produkcji, sam standardowy stack trace rzadko mówi ci dokładnie, dlaczego dane zostały odrzucone. Wiesz, że request się nie powiódł, ale jesteś całkowicie ślepy na rzeczywiste wartości wejściowe, które spowodowały crash. Właśnie ten problem rozwiązuje Real-World Observability z Logfire. Logfire to platforma do observability stworzona przez zespół Pydantic, która oferuje bezpośrednią integrację z samym Pydantic. Jej celem jest danie ci wglądu w to, co twoja warstwa walidacji danych faktycznie robi na produkcji. Zamiast traktować walidację jako czarną skrzynkę, która od czasu do czasu rzuca wyjątki, ta integracja zamienia każde sprawdzenie walidacji w śledzoną telemetrię. Wyobraź sobie background workera przetwarzającego rejestracje użytkowników z message queue. Setki eventów napływają w każdej sekundzie. Nagle jedna rejestracja kończy się błędem walidacji. Bez odpowiedniej instrumentacji, twoje logi pokazują generyczny crash. Musisz odszukać surowy payload z kolejki, żeby zorientować się, że użytkownik podał wiek minus pięć. Żeby to naprawić, importujesz paczkę Logfire i wywołujesz jedną funkcję o nazwie instrument underscore pydantic. Umieszczasz to zaraz po inicjalizacji twojego klienta Logfire. Od tego momentu twoje modele Pydantic są w pełni obserwowalne. Nie musisz zmieniać sposobu, w jaki definiujesz swoje modele, ani jak tworzysz ich instancje. Oto kluczowa sprawa. Po zinstrumentowaniu, za każdym razem, gdy Pydantic waliduje dane, Logfire automatycznie tworzy span. Span to po prostu zapis czasu trwania operacji. Jeśli payload rejestracji jest całkowicie poprawny, Logfire rejestruje udany span, pokazując dokładnie, ile czasu trwała walidacja. Jest to bardzo przydatne, jeśli masz złożone, customowe walidatory i musisz monitorować bottlenecki wydajnościowe. Jeśli payload jest niepoprawny, Pydantic rzuca błąd walidacji. Logfire łapie ten event i dołącza szczegóły do trace'a. Przechwytuje konkretny model i dokładne pola, które wywołały błąd. Kiedy patrzysz na swój dashboard observability, nie widzisz tylko generycznego komunikatu o błędzie. Widzisz dokładnie odrzucone wartości, takie jak ten ujemny wiek lub źle sformatowany string z e-mailem. Setup jest całkowicie bezobsługowy. Po pierwsze, skonfiguruj klienta. Po drugie, wywołaj funkcję instrument. Po trzecie, pozwól swojemu workerowi przetwarzać dane. Kiedy worker próbuje sparsować zły string JSON do twojego modelu rejestracji, telemetria automatycznie przechwytuje kontekst błędu. Nie piszesz absolutnie żadnych customowych bloków exception, żeby logować złe dane wejściowe. Ponieważ Logfire natywnie rozumie Pydantic, respektuje twoje struktury danych. Zna różnicę między brakującym polem a niezgodnością typów i formatuje tę telemetrię tak, abyś mógł ją później odpytać. Możesz filtrować swoje metryki, żeby dowiedzieć się dokładnie, ile razy pole e-mail nie przeszło walidacji w całym twoim klastrze workerów dzisiaj. Prawdziwą wartością tej integracji jest to, że podnosi ona walidację danych z prostego sprawdzania kodu do pierwszorzędnego eventu observability, przekształcając ciche odrzucenia danych w ustrukturyzowaną, actionable telemetrię. Jeśli chcesz wesprzeć podcast, znajdziesz nas, wyszukując DevStoriesEU na Patreonie. To wszystko w tym odcinku. Dzięki za wysłuchanie i buduj dalej!
7

Walidacja dowolnych typów za pomocą TypeAdapter

4m 09s

Dowiedz się, jak walidować samodzielne typy proste i listy bez tworzenia BaseModel. Odkryjesz, jak TypeAdapter zamienia dowolny typ w Pythonie w pełnoprawny cel walidacji.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 7 z 20. Czasami musisz po prostu zwalidować prostą listę stringów pochodzących z requestu API, ale tworzenie całej klasy modelu tylko po to, by trzymać tę jedną listę, to straszny overkill. Nie chcesz obiektu typu wrapper, chcesz po prostu zwalidowanej listy. Rozwiązaniem tego problemu jest walidacja dowolnych typów za pomocą TypeAdapter. W Pydantic standardowy workflow opiera się na definiowaniu klasy dziedziczącej po base model. Ten model daje ci dostęp do potężnych metod do parsowania i serializacji danych. Ale Pydantic doskonale radzi sobie z walidacją standardowych typów Pythona, takich jak zwykły dict, pojedynczy integer, standardowa dataclass czy typed dict. Haczyk polega na tym, że te standardowe typy nie posiadają natywnie metod walidacji z Pydantic. Nie możesz wywołać validate na standardowej liście w Pythonie. I tu wkracza type adapter. Działa jak most, wrappując dowolny typ Pythona i wystawiając dla niego wszystkie znane metody modelu. Wyobraź sobie endpoint, który przyjmuje surową tablicę stringów w JSON. Kiedyś pewnie stworzyłbyś dummy model z jednym polem o nazwie items, tylko po to, żeby przekazać do niego payload JSON. To zmusza klienta do wysłania obiektu JSON z kluczem items, albo zmusza cię do późniejszego rozpakowania zwalidowanego modelu. Dzięki type adapter całkowicie pomijasz dummy model. Najpierw tworzysz instancję adaptera i przekazujesz mu dokładnie taką definicję typu, jakiej oczekujesz. W tym przypadku przekazujesz type hint z Pythona dla listy stringów. To tworzy obiekt adaptera specjalnie skonfigurowany pod tę konkretną strukturę. Teraz masz dostęp do standardowych metod walidacji. Bierzesz surowy payload JSON ze swojego endpointu i przekazujesz go do metody validate json na instancji adaptera. Pydantic parsuje surowy byte string, sprawdza, czy to tablica JSON, weryfikuje, czy każdy element w środku to string, i zwraca standardową listę w Pythonie. Jeśli payload zawiera integer lub boolean, rzuca validation error dokładnie tak, jak zrobiłby to zwykły model. I tu jest kluczowa sprawa. Adapter nie ogranicza się do prostej walidacji. W pełni odzwierciedla core API standardowego modelu. To oznacza, że możesz go również używać do serializacji danych. Jeśli masz złożony dict lub standardową dataclass w Pythonie i musisz przekonwertować je z powrotem na JSON string, przekazujesz te dane do metody dump json na swoim adapterze. Stosuje on te same reguły serializacji, customowe encodery i formatowanie, które Pydantic stosuje do zwykłych modeli. Ta funkcja jest szczególnie przydatna podczas pracy z typed dicts. Typed dict zapewnia typowanie strukturalne dla standardowych dictów w Pythonie, ale nie wykonuje żadnej walidacji w runtime. Przekazując typed dict do adaptera, zyskujesz pełne wymuszanie struktury dicta w runtime. Zapewnia to obecność wszystkich wymaganych kluczy i zgodność wartości z oczekiwanymi typami, bez konwertowania dicta na instancję obiektu. Wynik pozostaje prostym dictem. Utworzenie instancji adaptera wymaga od Pydantic zbudowania wewnętrznych schematów walidacji. Ponieważ ten proces konfiguracji zajmuje trochę czasu obliczeniowego, powinieneś tworzyć instancje adaptera na poziomie modułu, zamiast przebudowywać je wewnątrz funkcji za każdym razem, gdy wywoływany jest endpoint. Zdefiniuj adapter raz na początku pliku i używaj go ponownie w wielu requestach. Type adapter daje ci pełną moc głównego silnika walidacji dla dowolnego standardowego typu w Pythonie, utrzymując twoje struktury danych w czystości i bez zbędnych klas typu wrapper. To wszystko na dziś. Dzięki za wysłuchanie — idź zbudować coś fajnego.
8

Typy Union i inteligentna walidacja

3m 37s

Zrozum złożoność walidacji typu Union. Dowiesz się, jak Smart Mode w Pydantic ocenia dokładność i prawidłowe pola, aby wybrać najlepsze dopasowanie.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 8 z 20. Kiedy pole ma adnotację Union ze stringiem lub integerem, a ty przekazujesz integer 123, którą walidację Pydantic tak naprawdę próbuje wykonać jako pierwszą? Jeśli założysz, że po prostu czyta twój kod od lewej do prawej, możesz się zdziwić, gdy twoje dane zachowają się inaczej, niż oczekujesz. To prowadzi nas do typów Union i Smart Validation. Typ Union pozwala jednemu polu akceptować wiele różnych typów danych. Walidacja typów Union jest z natury skomplikowana, ponieważ Pydantic aktywnie próbuje rzutować dane na żądany typ. Integer może łatwo stać się stringiem, a string zawierający cyfry może zostać sparsowany do integera. Gdyby silnik walidacji po prostu brał pierwsze znalezione dopasowanie, twój output zmieniałby się całkowicie w zależności od przypadkowej kolejności, w jakiej wypisałeś typy w kodzie. Takie sztywne zachowanie faktycznie istnieje i nazywa się trybem Left to Right. W tym trybie system sprawdza input względem pierwszego typu zdefiniowanego w Union. Jeśli walidacja się powiedzie, zatrzymuje się natychmiast. Jeśli się nie powiedzie, przechodzi do drugiego typu. Jeśli twoje pole ma typ string lub integer, dokładnie w tej kolejności, a ty przekażesz integer 123, tryb Left to Right najpierw sprawdzi warunek dla stringa. Ponieważ integer 123 może być bezproblemowo zrzutowany na stringa "123", walidacja przechodzi. Twój integer jest po cichu konwertowany na stringa tylko dlatego, że string został wpisany jako pierwszy. I tu pojawia się kluczowa kwestia. Domyślnie Pydantic unika tej pułapki, używając trybu Smart Mode. Zamiast zatrzymywać się na pierwszym akceptowalnym dopasowaniu, Smart Mode sprawdza input względem wszystkich możliwych typów w Union. Następnie porównuje udane walidacje i wybiera najlepsze dopasowanie na podstawie określonych kryteriów punktacji. Głównym kryterium dla prostych typów jest dokładność. Smart Mode mocno penalizuje rzutowanie danych. Wracając do naszego poprzedniego scenariusza z polem otypowanym jako string lub integer. Kiedy przekazujesz integer 123, Smart Mode testuje obie opcje. Zauważa, że input może zostać zrzutowany na prawidłowego stringa, ale widzi też, że ten input jest już idealnym, dokładnym dopasowaniem dla integera. Ponieważ dokładne dopasowanie zawsze wygrywa z dopasowaniem po rzutowaniu, Smart Mode poprawnie zwraca integer 123, niezależnie od tego, który typ został wpisany jako pierwszy w Union. Kiedy twój Union zawiera złożone modele danych, a nie podstawowe typy, Smart Mode opiera się na innej metryce. Zlicza liczbę ustawionych, prawidłowych pól. Silnik sprawdza wejściowy dictionary względem każdego modelu w Union. Oblicza, ile pól w inpucie dokładnie mapuje się na zdefiniowane pola każdego modelu. Model, który pomyślnie zaabsorbuje największą liczbę pól z inputu bez rzucania błędów walidacji, zostaje ogłoszony zwycięzcą. Zapobiega to pochłonięciu przez mniejszy, mniej specyficzny model danych, które były wyraźnie przeznaczone dla większego, bardziej szczegółowego modelu w tym samym Union. Smart Validation gwarantuje, że twoje dane zachowają swój dokładny, oryginalny kształt, kiedy tylko jest to możliwe, chroniąc cię przed cichymi błędami rzutowania, które są niezwykle trudne do wyśledzenia na produkcji. Dzięki za wysłuchanie, happy coding wszystkim!
9

Potężne narzędzie: Discriminated Unions

3m 55s

Zwiększ wydajność swojej walidacji. Dowiesz się, jak używać Discriminated (Tagged) Unions, aby dokładnie powiedzieć Pydantic, który schemat zastosować na podstawie określonego pola.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 9 z 20. Walidacja przychodzącego payloadu w oparciu o dwadzieścia różnych modeli danych metodą prób i błędów to koszmar wydajnościowy. Kiedy twój system odbiera generyczny event, zgadywanie, który schemat zastosować, marnuje cykle procesora i generuje bardzo mylące komunikaty o błędach, gdy walidacja się nie powiedzie. Możesz całkowicie ominąć tę grę w zgadywanie, korzystając z Power Toola: Discriminated Unions. Standardowy union mówi Pydanticowi, że pole może być jednym z kilku różnych modeli. Domyślnie Pydantic bierze przychodzące dane i próbuje je dopasować do pierwszego modelu. Jeśli to się nie uda, próbuje z drugim i tak dalej. Takie sekwencyjne parsowanie jest nieefektywne. Discriminated unions rozwiązują ten problem, używając jawnego tagu. Załóżmy, że budujesz pipeline analityczny, który odbiera różne typy eventów, takie jak click event, scroll event i purchase event. Każdy event wymaga innych pól danych. Model click może wymagać ID elementu, podczas gdy model purchase potrzebuje kwoty transakcji. Aby skonfigurować discriminated union, dodajesz współdzielone pole do każdego modelu w tej grupie. Możesz nazwać to pole event type. Następnie przypisujesz do tego pola typ literal string. Model click wymusza, aby event type był dokładnie stringiem click. Model purchase ściśle wymusza string purchase. Następnie tworzysz swój główny model payloadu. Ten model ma pojedyncze pole event, zdefiniowane jako union twoich konkretnych modeli eventów. To tutaj konfigurujesz discriminator. Opakowujesz definicję union w konfigurację pola Pydantic i przypisujesz string event type do argumentu discriminator. Oto kluczowa sprawa. Kiedy przychodzi payload, Pydantic nie testuje już modeli jeden po drugim. Patrzy bezpośrednio na klucz event type w przychodzących danych. Jeśli wartością jest purchase, Pydantic natychmiast kieruje cały payload do modelu purchase. To jest bezpośredni lookup. Jeśli brakuje kwoty transakcji, komunikat o błędzie jasno mówi, że brakuje wymaganego pola dla eventu purchase, zamiast generować ogromną ścianę tekstu wyjaśniającą, dlaczego dane nie dopasowały się do wszystkich możliwych typów eventów. To pokrywa czystą strukturę, w której każdy payload dzieli ten sam top-level key. Czasami masz do czynienia z nieustrukturyzowanymi danymi od third-party, gdzie identyfikujący tag jest zagnieżdżony w innym obiekcie, albo poprawny model zależy od obecności konkretnych kluczy, a nie od pojedynczej, dedykowanej wartości. Dla takich sytuacji Pydantic dostarcza callable discriminators. Zamiast przekazywać string z nazwą pola do argumentu discriminator, przekazujesz customową funkcję. Ta funkcja przyjmuje surowe, niezwalidowane dane wejściowe. Piszesz logikę wewnątrz tej funkcji, aby zbadać surowy słownik, znaleźć wskazówkę określającą typ danych i zwrócić prosty string tag reprezentujący poprawny model. Pydantic najpierw wykonuje twoją funkcję, otrzymuje z powrotem string tag i używa go, aby skierować dane do precyzyjnego modelu w unionie. Użycie discriminated union przekształca walidację z sekwencyjnej gry w zgadywanie w precyzyjny lookup w czasie stałym. Dzięki za wysłuchanie, życzę wszystkim miłego dnia!
10

Przetwarzanie wstępne z Before Validators i Wrap Validators

3m 53s

Poradź sobie z nieuporządkowanymi danymi wejściowymi, zanim trafią do twojego schematu. Dowiesz się, jak używać walidatorów pól Before i Wrap, aby wyczyścić surowe dane wejściowe, zanim Pydantic je oceni.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 10 z 20. Czasami twoje dane wejściowe są tak chaotyczne, że standardowe parsowanie sypie się w momencie, gdy tylko dotkną twojego modelu. Musisz przechwycić i oczyścić surowy input, zanim framework w ogóle spróbuje go odczytać. Właśnie to umożliwia ci pre-processing za pomocą walidatorów Before i Wrap. Pydantic zazwyczaj doskonale radzi sobie z automatycznym rzutowaniem danych na właściwy typ. Ale jeśli podstawowy kształt danych jest całkowicie zły, rzutowanie natychmiast zawodzi. Walidator Before został zaprojektowany właśnie do tego problemu. To funkcja podpięta pod pole, która wykonuje się, zanim Pydantic zrobi jakiekolwiek własne sprawdzanie typów czy konwersję. Otrzymuje surowy, nietknięty input dokładnie w takiej postaci, w jakiej został przekazany do modelu. Wyobraź sobie scenariusz, w którym twój model definiuje pole ściśle wymagające listy intów. Jednak konsumujesz zewnętrzne API, które błędnie wysyła te dane jako pojedynczy, ciągły string liczb oddzielonych przecinkami, na przykład string jeden przecinek dwa przecinek trzy. Pydantic oczekuje tablicy, widzi pojedynczy string i odrzuca go z błędem walidacji. Naprawiasz to, pisząc walidator Before. Wewnątrz swojej funkcji walidatora patrzysz na surowy input. Sprawdzasz, czy wartość jest stringiem. Jeśli tak, dzielisz ten string po każdym przecinku, co tworzy listę pojedynczych znaków jako stringi. Nie musisz samodzielnie konwertować tych znaków na inty. Po prostu zwracasz nowo utworzoną listę. Pydantic przejmuje stąd stery. Widzi listę, której oczekiwał, odpala swoje standardowe wewnętrzne rzutowanie i zamienia te wartości typu string na inty za ciebie. Musiałeś tylko naprawić strukturalny kształt danych. To tyle, jeśli chodzi o inputy przetwarzane przed główną logiką. Kolejnym poziomem kontroli jest walidator Wrap. Walidatory Wrap to najbardziej elastyczne narzędzie do walidacji, jakie oferuje Pydantic. Zamiast odpalać się tylko przed etapem walidacji, walidator Wrap dosłownie otacza wewnętrzny silnik walidacji Pydantic dla tego pola. Kiedy piszesz walidator Wrap, twoja funkcja otrzymuje dwa argumenty. Pierwszym jest surowy input, tak samo jak w walidatorze Before. Drugim argumentem jest handler. Ten handler reprezentuje główną logikę walidacji i rzutowania w Pydantic. I tu zaczyna się robić ciekawie. To ty decydujesz dokładnie kiedy, a nawet czy w ogóle, ten handler się wykona. Flow logiki jest całkowicie w twoich rękach. Możesz zbadać surowy input i go zmodyfikować. Następnie jawnie wywołujesz handler, przekazując mu swoje oczyszczone dane. Pydantic odpala swoje wewnętrzne sprawdzanie typów na tym, co dostarczyłeś, i zwraca w pełni sparsowaną wartość z powrotem do twojego walidatora. Możesz wtedy ponownie zmodyfikować tę sparsowaną wartość przed przekazaniem jej do ostatecznego modelu. Ponieważ to ty kontrolujesz, kiedy handler się wykonuje, możesz umieścić go w standardowym bloku try except. Jeśli wewnętrzna walidacja Pydantic wyrzuci błąd, łapiesz go dokładnie tam, w walidatorze Wrap. Możesz zalogować błąd, zmienić dane i spróbować ponownie, albo po prostu zwrócić bezpieczną wartość domyślną. Możesz nawet napisać logikę, która całkowicie pomija handler dla pewnych specyficznych inputów, omijając standardową walidację w całości. Walidatory Before oczyszczają nieprawidłowy kształt inputów, żeby Pydantic mógł je odczytać, podczas gdy walidatory Wrap dają ci całkowitą władzę nad całym cyklem życia walidacji wokół pojedynczego pola. To wszystko w tym odcinku. Dzięki za wysłuchanie i twórzcie dalej!
11

Przetwarzanie końcowe z After Validators i Plain Validators

3m 37s

Wymuszaj surowe reguły logiki biznesowej. Dowiesz się, jak używać After Validators do weryfikacji już sparsowanych danych oraz Plain Validators, aby całkowicie pominąć standardową walidację Pydantic.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 11 z 20. Sprawdzenie, czy string wygląda jak format e-maila, jest proste. Weryfikacja, czy dane spełniają ścisłą logikę biznesową, na przykład przez odpytanie zewnętrznego systemu albo wymuszenie konkretnych reguł matematycznych, wymaga bezpiecznego miejsca do uruchomienia customowego kodu. Właśnie to zapewnia post-processing z użyciem walidatorów After i Plain. Kiedy definiujesz pole w modelu Pydantic, biblioteka automatycznie sprawdza input pod kątem type hinta. Same typy to jednak za mało. Integer to integer, niezależnie od tego, czy to jeden, czy milion. Aby wymusić reguły wykraczające poza podstawowe typy, dodajesz customowe funkcje walidacyjne. Pydantic pozwala ci wstrzyknąć te funkcje w cykl życia walidacji. Najczęstszym punktem wstrzyknięcia jest walidator After. Jak sama nazwa wskazuje, uruchamia się on po tym, jak Pydantic skończy swoje wewnętrzne parsowanie i type coercion. I tu jest kluczowa sprawa. Kiedy twoja customowa funkcja otrzymuje dane w walidatorze After, Pydantic gwarantuje, że pasują one już do typu pola. Nie musisz pisać boilerplate'u do obsługi konwersji typów ani łapania nieoczekiwanych typów danych. Wyobraź sobie scenariusz, w którym musisz upewnić się, że pole typu integer jest liczbą parzystą. Definiujesz model z polem typu integer. Następnie piszesz customową funkcję, która przyjmuje wartość jako argument. Ponieważ konfigurujesz tę funkcję jako walidator After, masz pewność, że wartość jest absolutnie integerem. Po prostu używasz operatora modulo, żeby sprawdzić, czy dzielenie wartości przez dwa zostawia resztę. Jeśli reszta nie jest zerem, rzucasz standardowy pythonowy ValueError z customową wiadomością. Jeśli reszta to zero, zwracasz wartość. Pydantic bierze tę zwróconą wartość i przypisuje ją do modelu. Podział pracy jest jasny. Pydantic wymusza typ, a ty wymuszasz regułę biznesową. Czasami domyślne parsowanie Pydantica wchodzi ci w drogę. I tu wkracza walidator Plain. Walidator Plain całkowicie zastępuje wewnętrzną walidację Pydantica dla konkretnego pola. Pydantic odsuwa się na bok i przekazuje surowy, niezwalidowany input bezpośrednio do twojej customowej funkcji. Używasz walidatora Plain, kiedy standardowe reguły type coercion nie pasują do twojego use case'u, albo kiedy masz do czynienia z mocno customową strukturą danych, której Pydantic natywnie nie rozumie. W tym scenariuszu twoja funkcja odpowiada za wszystko. Odbiera surowy input, wykonuje niezbędne sprawdzanie typów, konwertuje dane i stosuje logikę biznesową. Jeśli coś pójdzie nie tak, twoja funkcja musi rzucić ValueError albo AssertionError. Jeśli się uda, zwraca ostateczną, czystą wartość dla modelu. Oba te walidatory podpinasz do pól używając dekoratorów Pydantica na metodach klasy, albo dodając je jako metadane bezpośrednio wewnątrz type hinta za pomocą adnotacji. Wybór między nimi sprowadza się do tego, ile pracy chcesz wykonać samodzielnie. Użyj walidatora After, kiedy chcesz, żeby Pydantic odwalił najcięższą robotę przy konwersji typów, a po walidator Plain sięgaj tylko wtedy, gdy potrzebujesz absolutnej kontroli nad parsowaniem surowego inputu od zera. Dzięki, że słuchasz — do usłyszenia następnym razem.
12

Hooki walidacyjne na poziomie modelu

3m 48s

Waliduj interakcje między wieloma polami. Dowiesz się, jak używać dekoratora model_validator, aby wymuszać reguły zależne od całego payloadu.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 12 z 20. Walidacja pól w izolacji działa idealnie, aż do momentu, gdy twoja logika biznesowa narzuci, że pole B może być ustawione tylko wtedy, gdy pole A ma konkretną wartość. Kiedy integralność danych zależy od interakcji wielu pól, potrzebujesz hooków walidacji na poziomie modelu. W Pydantic współzależne pola obsługujesz za pomocą dekoratora model validator. W przeciwieństwie do field validators, które skupiają się na pojedynczym fragmencie danych wejściowych, model validator analizuje całą strukturę danych naraz. Pydantic oferuje trzy tryby dla tego dekoratora: before, after i wrap. Określają one dokładnie, kiedy twoja własna logika wykonuje się podczas cyklu życia parsowania. Zastosujmy to do standardowego modelu rejestracji użytkownika. Masz dwa pola: password i password repeat. Sprawdzenie na poziomie pola może zweryfikować długość lub złożoność, ale nie potrafi ich ze sobą porównać. Do tego używasz model validator w trybie after. Tryb after wykonuje się, gdy Pydantic pomyślnie sparsuje i zwaliduje wszystkie pojedyncze pola. Na tym etapie twoja funkcja walidująca otrzymuje samą instancję modelu. Po prostu piszesz logikę, która sprawdza, czy atrybut password modelu jest równy atrybutowi password repeat. Jeśli się różnią, rzucasz ValueError. Oto kluczowa sprawa. Używając trybu after, twoja funkcja musi jawnie zwrócić instancję modelu, zazwyczaj nazywaną self, na końcu metody. Jeśli zapomnisz zwrócić self, Pydantic odrzuci twoje zwalidowane dane i nie zwróci niczego. Czasami musisz przechwycić dane wcześniej. Wtedy do gry wchodzi tryb before. Model validator w trybie before uruchamia się, zanim Pydantic spróbuje jakiegokolwiek parsowania czy rzutowania typów. Zamiast otypowanej instancji modelu, twoja funkcja otrzymuje surowe dane wejściowe, którymi zazwyczaj jest słownik. Używasz tego trybu, gdy surowa struktura danych jest chaotyczna i wymaga dostosowania, zanim standardowa walidacja w ogóle się rozpocznie. Na przykład, jeśli starsze żądania API wysyłają konfiguracje haseł w zagnieżdżonym słowniku, before validator może wyciągnąć te stringi i spłaszczyć je do kluczy najwyższego poziomu, których oczekuje twój model Pydantic. Następnie funkcja zwraca zmodyfikowany słownik, przekazując go dalej w chainie. Trzeci tryb to wrap. Służy on do całkowitej kontroli nad cyklem życia walidacji. Wrap validator przyjmuje surowe dane wejściowe i funkcję handler. Uruchamiasz swoją logikę pre-processingu, jawnie wywołujesz handler, aby wyzwolić wewnętrzną walidację Pydantic, a następnie uruchamiasz post-processing na wyniku. Używasz tego, gdy musisz przechwycić wewnętrzne błędy walidacji Pydantic, zalogować je do zewnętrznego systemu i być może zwrócić zmodyfikowaną wiadomość o błędzie lub domyślny obiekt fallback. Wybór odpowiedniego trybu to po prostu kwestia timingu. Używaj before do kształtowania surowych danych wejściowych, after do porównywania silnie typowanych pól, a wrap do kontrolowania samego wykonania walidacji. Jeśli uważasz te odcinki za przydatne i chcesz wesprzeć program, możesz wyszukać DevStoriesEU na Patreonie. To wszystko w tym odcinku. Do usłyszenia następnym razem!
13

Serializacja: Bezpieczne zrzucanie danych

4m 08s

Kontroluj, jak twoje dane opuszczają system. Poznasz różnice między zrzucaniem do Python dicts a ciągami JSON oraz dowiesz się, jak wykluczać nieustawione lub domyślne pola.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 13 z 20. Wprowadzenie prawidłowych danych do systemu to dopiero połowa sukcesu. Kiedy przychodzi czas, aby zwrócić te dane na frontend, często okazuje się, że twoje payloady są przeładowane pustymi polami i wartościami domyślnymi, których użytkownik tak naprawdę nigdy nie podał. Serializacja, czyli bezpieczne dumpowanie danych, to sposób na uporządkowanie tego ruchu wychodzącego. Gdy dane siedzą już bezpiecznie w modelu Pydantic, w końcu musisz je wyciągnąć, aby wysłać je gdzieś indziej. Masz na to dwa główne sposoby. Pierwszy to wywołanie model dump. Ta metoda odczytuje twój model i zwraca zwykły pythonowy dictionary. Drugi to wywołanie model dump json. Ta metoda pomija etap dictionary i zwraca w pełni sformatowany string JSON, gotowy do wysłania w świat. Różnica między nimi jest nieco głębsza niż tylko dictionary a string. Sprowadza się do trybów serializacji. Domyślnie model dump działa w trybie Pythona. Jeśli twój model zawiera typ złożony, taki jak obiekt datetime, wynikowy dictionary nadal będzie zawierał pythonowy obiekt datetime. Z drugiej strony, model dump json działa w trybie JSON. JSON nie wie, czym jest pythonowy obiekt datetime, więc Pydantic automatycznie konwertuje go na standardową reprezentację w postaci stringa. Oto kluczowa sprawa. Możesz tak naprawdę wymusić, aby wynikowy dictionary używał trybu JSON. Jeśli wywołasz model dump i przekażesz argument mode ustawiony na json, Pydantic zwróci dictionary, w którym wszystkie typy złożone zostały już przetłumaczone na podstawowe, bezpieczne dla JSON formaty, takie jak stringi i integery. To załatwia sprawę typów, ale nadal musisz zarządzać kształtem payloadu. Weźmy na przykład model profilu użytkownika zwracający dane na frontend. Model może definiować dwadzieścia możliwych pól. Nowy użytkownik rejestruje się i podaje tylko swoje imię i email. Pozostałe osiemnaście pól przyjmuje wartości domyślne, takie jak puste stringi, nulle lub domyślne URL-e awatarów. Jeśli zrobisz dump tego modelu w normalny sposób, wyślesz wszystkie dwadzieścia pól na frontend. Aby to naprawić, Pydantic udostępnia trzy konkretne keyword argumenty, które możesz przekazać do obu metod dump. Najbardziej precyzyjnym z nich jest exclude unset. Kiedy ustawisz exclude unset na true, Pydantic dokładnie śledzi, które pola zostały wypełnione podczas tworzenia modelu. Zrobi dump tylko imienia i emaila. Osiemnaście domyślnych pól jest całkowicie pomijanych w dictionary lub stringu JSON. Dzięki temu masz pewność, że nigdy nie wyciekną dane domyślne, których użytkownik tak naprawdę nie przesłał. Jeśli oczekujesz nieco innego zachowania, możesz użyć exclude defaults. Ta flaga mówi Pydantic, aby pominął każde pole, które obecnie pasuje do swojej wartości domyślnej. Nie ma znaczenia, czy użytkownik jawnie przesłał tę wartość domyślną, czy system wypełnił ją automatycznie. Jeśli wartość jest zgodna z domyślną, zostaje usunięta z outputu. Na koniec mamy exclude none. Ustaw to na true, a Pydantic usunie każde pole, w którym wartość wynosi obecnie none. Jest to wyłącznie sprawdzenie wartości, które całkowicie ignoruje wartości domyślne czy śledzenie unset. Te flagi wykluczeń dają ci ścisłą kontrolę nad ruchem sieciowym i odpowiedziami API. Zadbaj o to, aby twoje modele wewnętrzne były w pełni kompletne, ale korzystaj z metod dump, aby upewnić się, że twoje zewnętrzne payloady pozostają dokładnie tak lekkie, jak to konieczne. Dzięki za uwagę. Do następnego razu!
14

Dostosowywanie logiki serializacji

2m 48s

Zmień sposób reprezentacji swoich typów na wyjściu. Dowiesz się, jak pisać niestandardowe serializatory Field i Model, aby modyfikować dane podczas fazy zrzucania.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 14 z 20. Co jeśli przechowujesz datę wewnętrznie jako obiekt datetime w Pythonie, ale twój kontrakt frontendowego API wymaga surowego Unix timestampa w postaci integera? Mógłbyś przeiterować po danych tuż przed ich wysłaniem, ale to mało eleganckie i podatne na błędy. Czystszym rozwiązaniem jest dostosowanie logiki serializacji bezpośrednio w twoich modelach Pydantic. Pydantic daje ci dekoratory, które przechwytują dokładny moment, w którym model zamienia się z powrotem w dictionary lub JSON-a. Zaczniemy od field serializerów. Field serializer celuje w konkretny atrybut. Aby go stworzyć, piszesz zwykłą metodę w klasie swojego modelu i umieszczasz dekorator field serializer bezpośrednio nad nią. Przekazujesz dekoratorowi nazwę pola, które chcesz zmodyfikować. Wykorzystajmy ten scenariusz z datetime. Masz model z atrybutem o nazwie created at, otypowanym jako standardowy Pythonowy datetime. Wewnątrz modelu tworzysz metodę o nazwie serialize created at. Nazwa metody nie ma znaczenia. Nad nią umieszczasz dekorator field serializer, wskazujący na pole created at. Metoda przyjmuje wartość datetime jako swój input. Wewnątrz metody wywołujesz standardową funkcję timestamp na tym obiekcie datetime i zwracasz wynikowy integer. Teraz, za każdym razem, gdy model dumpuje swoje dane, Pydantic przechwytuje pole created at, uruchamia twoją customową metodę i zwraca czysty integer zamiast stringa w formacie ISO. Oto kluczowa rzecz. Serializery działają w dwóch różnych trybach: plain i wrap. Tryb plain jest domyślny. Gdy serializer działa w trybie plain, Pydantic całkowicie odrzuca swoją wewnętrzną logikę dla tego pola i uruchamia tylko twój customowy kod. To jest pełny override. Ale czasami musisz najpierw uruchomić domyślną logikę, a dopiero potem zmodyfikować wynik. Albo może chcesz złapać błędy wokół domyślnego zachowania. Wtedy właśnie używasz trybu wrap. Aby go włączyć, przekazujesz do dekoratora argument mode equals wrap. W trybie wrap twoja metoda otrzymuje drugi argument o nazwie handler. Ten handler jest referencją do wewnętrznej logiki serializacji Pydantic. Możesz wywołać handler, aby uzyskać domyślny output, zbadać go, zmodyfikować lub zrobić do niego fallback, jeśli twoja customowa logika zawiedzie. To pokrywa temat pojedynczych pól. Jeśli musisz zmienić strukturę całego outputu, używasz model serializera. Setup jest prawie identyczny, ale dekorator ląduje nad metodą, która operuje na całej instancji modelu. Zamiast otrzymywać wartość pojedynczego pola, metoda uzyskuje dostęp do atrybutów samego modelu. Jeśli ustawisz model serializer w tryb plain, zwracasz zupełnie nową strukturę dictionary od zera. Jeśli ustawisz go w tryb wrap, twoja metoda przyjmuje argument handlera, dokładnie tak jak field serializer. Wywołujesz handler, aby najpierw uzyskać standardowe dictionary modelu. Następnie możesz dodać nowe klucze na najwyższym poziomie, usunąć prywatne dane lub spłaszczyć zagnieżdżone struktury przed zwróceniem ostatecznego dictionary. Najpotężniejszym aspektem tych dekoratorów jest to, że rozdzielają twoje wewnętrzne typy Pythona od zewnętrznych kontraktów API, utrzymując ścisłą walidację na wejściu i precyzyjne formatowanie na wyjściu. To wszystko w tym odcinku. Dzięki za wysłuchanie i buduj dalej!
15

Generowanie JSON Schema z modeli

3m 59s

Zamień swoje modele w samodokumentujące się kontrakty API. Dowiesz się, jak generować zgodne z OpenAPI JSON Schemas i wstrzykiwać przykłady bezpośrednio do schematu.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 15 z 20. Jeśli twoje schematy API są już ściśle typowane w Pythonie, konieczność utrzymywania oddzielnego pliku YAML dla dokumentacji OpenAPI to ogromna strata czasu. W efekcie utrzymujesz dwa źródła prawdy, które nieuchronnie się od siebie oddalają. Generowanie JSON Schema bezpośrednio z twoich modeli rozwiązuje ten problem z synchronizacją. Każdy model Pydantic ma metodę o nazwie model json schema. Kiedy wywołujesz tę metodę, Pydantic analizuje twój model. Odczytuje pola, typy, wartości domyślne i ograniczenia walidacyjne. Następnie tłumaczy całą tę wewnętrzną logikę Pythona na standardowy słownik JSON Schema. Dokładniej mówiąc, Pydantic generuje Draft 2020-12 specyfikacji JSON Schema. I to jest najważniejsze. Ponieważ output jest zgodny z tym powszechnie akceptowanym standardem, jest natywnie kompatybilny z OpenAPI. Definiujesz swoje ścisłe reguły walidacji raz w Pythonie, a framework automatycznie dostarcza dokładną definicję schematu, której potrzebują twoi zewnętrzni konsumenci. Nie musisz niczego tłumaczyć ręcznie. Standardowe generowanie schematu doskonale radzi sobie z typami i podstawowymi ograniczeniami. Ale czasami musisz przekazać logikę biznesową lub specyficzne formaty, których nie da się wywnioskować z samego type hinta w Pythonie. Wyobraź sobie scenariusz, w którym budujesz model Configuration dla nowej usługi. Model zawiera pole, które przyjmuje słownik z customowymi ustawieniami. Zespół frontendowy musi dokładnie wiedzieć, jak wygląda poprawny payload, a nie tylko, że jest to generyczny obiekt. Aby to rozwiązać, używasz funkcji o nazwie json schema extra. Ten parametr pozwala ci wstrzyknąć dowolne customowe metadane bezpośrednio do wygenerowanego JSON Schema. Możesz go użyć, żeby dodać mockowe przykłady, customowe opisy albo specyficzne markery słów kluczowych, których może wymagać twój API gateway. Możesz zastosować json schema extra na dwóch różnych poziomach. Możesz przypiąć go do pojedynczego pola albo zastosować do całego modelu. Żeby dostarczyć mockowy przykład dla tego konkretnego pola z ustawieniami, definiujesz swój model Configuration. Do atrybutu ze złożonymi ustawieniami przypisujesz funkcję Field. Wewnątrz tej funkcji Field podajesz argument json schema extra. Przekazujesz do niego słownik zawierający standardowy klucz JSON Schema o nazwie examples. Wartość zmapowana na ten klucz to lista zawierająca twój dokładny mockowy payload konfiguracyjny. Alternatywnie, jeśli chcesz udokumentować cały model, a nie pojedyncze pole, definiujesz słownik model config w klasie. Wewnątrz tego słownika konfiguracyjnego podajesz json schema extra z przykładem na poziomie schematu. To podejście jest bardzo przydatne, kiedy chcesz pokazać, jak wiele pól współpracuje ze sobą w kompletnym request body. Kiedy wywołujesz model json schema na swoim modelu Configuration, Pydantic buduje standardowe drzewo schematu. Kiedy dociera do twoich pól lub konfiguracji modelu, scala twój słownik z customowymi przykładami bezpośrednio ze standardowym outputem. Narzędzia frontendowe odczytują ten schemat, parsują właściwość examples i natychmiast wyświetlają mockowy payload programistom. Wiedzą dokładnie, co wysłać, a twój kod w Pythonie pozostaje jedynym źródłem prawdy. Prawdziwą siłą generowania schematów w Pydantic jest to, że każde zewnętrzne narzędzie stworzone dla ekosystemu JSON Schema może natychmiast skonsumować twoje reguły walidacji z Pythona bez żadnej customowej integracji. Dzięki za spędzenie ze mną tych kilku minut. Do usłyszenia następnym razem, trzymaj się.
16

RootModel: Gdy twój payload nie jest słownikiem

3m 36s

Elegancko obsługuj niestandardowe payloady JSON. Odkryjesz, jak RootModel pozwala parsować tablice i typy proste na poziomie głównym, zachowując przy tym możliwości BaseModel.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 16 z 20. Standardowe modele zakładają, że twój przychodzący payload JSON to obiekt zmapowany na klucze i wartości. Ale co się stanie, gdy endpoint musi bezpośrednio przyjąć top-level array, albo po prostu zwykły string, bez owijania go w dictionary? Właśnie do tego został stworzony RootModel: gdy twój payload nie jest dictionary. Kiedy używasz standardowego base model, Pydantic mapuje atrybuty twojej klasy na klucze JSON. Jeśli wyślesz do standardowego modelu surową listę, na przykład JSON array z liczbami, walidacja się nie powiedzie. Oczekuje struktury dictionary. Aby to obejść, developerzy często zmuszają klienta do zmiany payloadu. Tworzą sztuczny klucz, na przykład o nazwie items, i owijają array w obiekt. W efekcie naginasz design swojego API tylko po to, żeby zadowolić bibliotekę do walidacji. RootModel eliminuje ten problem. To specjalny model Pydantic zaprojektowany specjalnie dla payloadów, w których najbardziej zewnętrzną strukturą jest lista, tupla, albo typ prosty, taki jak integer czy string. Weźmy na przykład endpoint do bulk-delete. Chcesz, żeby klient wysłał surowy JSON array zawierający integery z ID użytkowników i nic więcej. Żeby to obsłużyć, importujesz RootModel z Pydantic. Definiujesz nową klasę, na przykład o nazwie UserIdList, która dziedziczy po RootModel. Parametryzujesz to dziedziczenie listą integerów. Kiedy surowy JSON array dociera na serwer, przekazujesz go bezpośrednio do metody model validate w twojej klasie UserIdList. Pydantic natywnie akceptuje ten top-level array. Iteruje po payloadzie, upewnia się, że każdy pojedynczy element to prawidłowy integer, i zwraca w pełni zwalidowaną instancję modelu. I tu jest kluczowa sprawa. Mimo że RootModel waliduje płaską listę, zapewnia dokładnie taki sam interfejs jak zwykły model. Nadal masz dostęp do standardowych metod. Możesz wywołać model dump, żeby przekonwertować dane z powrotem na obiekty Pythona, albo model dump json, żeby wygenerować surowy string. Ponieważ w twoim payloadzie nie ma nazwanych pól, potrzebujesz sposobu na dostęp do danych po ich zwalidowaniu. Pydantic przechowuje sparsowane dane w pojedynczym atrybucie o nazwie dokładnie root. Jeśli chcesz przeiterować po tych zwalidowanych user ID, po prostu iterujesz po atrybucie root w swojej instancji modelu. Ten mechanizm nie ogranicza się tylko do list. Możesz zdefiniować RootModel dla pojedynczego stringa albo integera. Jeśli otrzymasz payload w postaci samego stringa, ale musisz przepuścić go przez restrykcyjne sprawdzanie długości albo pattern matching, zdefiniowanie go jako RootModel typu string pozwala ci natywnie podpiąć te reguły walidacji. Dane pozostają prostym stringiem w payloadzie, ale zyskują pełną ochronę silnika do walidacji. Zawsze, gdy łapiesz się na wymyślaniu klucza w dictionary tylko po to, żeby Pydantic miał co sparsować, używasz złego narzędzia. Użyj RootModel, żeby dostosować swoją warstwę walidacji do kontraktu API, zamiast modyfikować kontrakt API, żeby zadowolić warstwę walidacji. Dzięki za wysłuchanie. Trzymajcie się wszyscy.
17

Standardowe Dataclasses a Pydantic Dataclasses

3m 58s

Wprowadź walidację do swoich natywnych klas Pythona. Dowiesz się, kiedy używać dekoratora dataclass z Pydantic, aby zmodernizować starsze bazy kodu bez przepisywania wszystkiego.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 17 z 20. Masz ogromny codebase zbudowany w całości na standardowych dataclasses w Pythonie i zdajesz sobie sprawę, że desperacko potrzebujesz walidacji w runtime. Możesz myśleć, że musisz wszystko przepisać, żeby dziedziczyć z BaseModel. Wcale nie musisz. Dzisiaj przyjrzymy się standardowym dataclasses w porównaniu do dataclasses z Pydantica. Standardowa biblioteka Pythona oferuje dekorator dataclass, który doskonale nadaje się do redukcji boilerplate'u. Pisze za ciebie metody inicjalizacji, reprezentacji i równości. Jednak ślepo ufa twoim inputom. Jeśli zadeklarujesz atrybut age jako integer i przekażesz mu string, standardowa dataclass po prostu ten string zaakceptuje. Dostarcza type hints do analizy statycznej, ale oferuje zerowe bezpieczeństwo w runtime. Pydantic rozwiązuje ten problem dzięki własnemu dekoratorowi dataclass. Został on zaprojektowany specjalnie jako drop-in replacement dla wersji ze standardowej biblioteki. Zachowujesz dokładnie tę samą strukturę klas. Nie dodajesz żadnych klas bazowych. Zmieniasz tylko instrukcję import, żeby zaciągnąć dekorator z modułu pydantic dot dataclasses zamiast ze standardowej biblioteki. Weźmy ten legacy codebase zbudowany na standardowych dataclasses. Znajdujesz dataclass obsługującą obiekt konfiguracji. Zamieniasz standardowy dekorator na dekorator Pydantica. Od razu, gdy twoja aplikacja tworzy ten obiekt konfiguracji, Pydantic przechwytuje inicjalizację. Odczytuje twoje istniejące type hints i je egzekwuje. Jeśli przekazany zostanie nieprawidłowy typ, Pydantic próbuje wykonać coercion. Jeśli coercion się nie powiedzie, natychmiast rzuca błąd walidacji. Zyskujesz ścisłe, sprawdzane pod kątem typów przypisania z zerowymi zmianami strukturalnymi w twoim drzewie dziedziczenia. Oto kluczowa sprawa. Skoro obie opcje dają ci walidację, musisz zrozumieć różnicę między dataclass z Pydantica a standardowym BaseModel. Obsługują one dane pod spodem w zupełnie inny sposób. BaseModel jest w gruncie rzeczy zbudowany wokół parsowania słowników i zapewnia szeroki zakres wbudowanych metod do eksportowania danych. Dataclass z Pydantica pozostaje w swojej istocie standardową klasą w Pythonie, zachowując swój tradycyjny memory footprint i zachowanie. Ponieważ pozostaje ona standardową klasą, sposób, w jaki Pydantic aplikuje walidację, jest inny. Kiedy tworzysz instancję dataclass z Pydantica, argumenty są kopiowane. Dane przechodzą przez główny silnik walidacji Pydantica, który parsuje i konstruuje nowe obiekty, żeby dopasować je do twoich type hints. Nie tworzy jedynie referencji do oryginalnych, mutowalnych inputów, które przekazałeś. Jeśli przekażesz listę do dataclass z Pydantica, walidator ją przetworzy, zwaliduje wewnętrzne elementy i przypisze do instancji zupełnie nową listę. Oryginalna lista z inputu i atrybut w twojej dataclass nie są już tym samym obiektem w pamięci. To zachowanie polegające na kopiowaniu zapewnia, że twoje dane ściśle trzymają się schematu bez mutowania oryginalnych zmiennych z inputu. Główną zaletą dataclass z Pydantica jest wypełnienie luki między standardowymi paradygmatami Pythona a rygorystyczną walidacją. Jeśli potrzebujesz czystej ścieżki migracji dla legacy code, który już korzysta ze standardowych dataclasses, po prostu podmień dekorator, żeby uzyskać natychmiastowe type safety, zachowując jednocześnie całą istniejącą semantykę klas. Jeśli podoba ci się podcast i chcesz wesprzeć program, wyszukaj DevStoriesEU na Patreonie. To wszystko w tym odcinku. Dzięki za słuchanie i buduj dalej!
18

Dostrajanie konfiguracji modelu

3m 35s

Kontroluj rygorystyczność całego modelu. Dowiesz się, jak używać ConfigDict, aby zabronić dodatkowych atrybutów, zamrażać instancje i walidować przypisania.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 18 z 20. Domyślnie Pydantic po cichu ignoruje wszelkie dodatkowe klucze JSON, które mu wyślesz. W restrykcyjnym API przepuszczanie nieznanych danych bez ostrzeżenia to ogromne ryzyko bezpieczeństwa. Aby to naprawić, potrzebujesz precyzyjnego dostrojenia konfiguracji modelu. Aby zmienić globalne zachowanie modelu, definiujesz atrybut klasy o nazwie model config. Przypisujesz do niego ConfigDict, czyli typowany słownik importowany bezpośrednio z Pydantic. Umieszczasz to przypisanie bezpośrednio w swoim modelu, obok definicji pól. Ponieważ ConfigDict jest typowany, twój edytor kodu wychwyci literówki, jeśli spróbujesz przekazać nieprawidłową opcję konfiguracji. Zasady, które umieścisz w tym słowniku, podyktują, jak cały model parsuje, waliduje i przechowuje dane. Zbudujmy restrykcyjny model ustawień bezpieczeństwa dla aplikacji. Złośliwy klient może wysłać payload JSON z nieoczekiwanymi polami, próbując na przykład wstrzyknąć flagę admina lub nadpisać ukryty parametr. Domyślnie Pydantic ustawia zachowanie dla dodatkowych pól na ignore. Odczytuje pola, których oczekuje, po cichu całkowicie odrzuca nieznane dane i tworzy model. Aby zamknąć tę lukę, dodajesz parametr extra do swojego ConfigDict i ustawiasz jego wartość na string forbid. Teraz, jeśli klient wyśle nieoczekiwany klucz, Pydantic natychmiast rzuci błąd walidacji. Request od razu kończy się błędem, jawnie odrzucając błędny payload, zanim logika twojej aplikacji w ogóle go przetworzy. To załatwia sprawę granicy między światem zewnętrznym a twoim systemem. Ale co dzieje się wewnątrz twojego systemu po utworzeniu modelu? Pydantic zazwyczaj waliduje dane tylko podczas inicjalizacji. Jeśli inny programista napisze później kod, który zmienia atrybut na istniejącej instancji modelu, Pydantic nie wchodzi mu w drogę. Mógłbyś przypadkowo przypisać surowy string do pola typu integer, a model by to zaakceptował. Aby temu zapobiec, możesz ustawić validate assignment na true w swoim ConfigDict. Z tą włączoną opcją, za każdym razem, gdy atrybut jest modyfikowany w pamięci, Pydantic przechwytuje zmianę i uruchamia dokładnie tę samą logikę walidacji, której używa podczas tworzenia. Czasami nawet walidacja mutacji jest zbyt pobłażliwa dla konfiguracji bezpieczeństwa. Możesz chcieć absolutnej gwarancji, że ustawienia nie mogą zostać zmodyfikowane w pamięci przez żadną część twojego kodu po przejściu początkowego sprawdzenia. I tu robi się ciekawie. Możesz ustawić parametr frozen na true w konfiguracji swojego modelu. To sprawia, że cała instancja modelu staje się niemutowalna. Jeśli jakakolwiek funkcja w dalszej części kodu spróbuje zaktualizować pole, Pydantic rzuci błąd. Zamrożony model działa dokładnie tak samo jak krotka w Pythonie. Ponieważ nie może się zmienić, zamrożony model jest całkowicie bezpieczny do współdzielenia między różnymi częściami twojej aplikacji, a nawet może być bezpiecznie używany jako klucz w słowniku w Pythonie lub w cache'u w pamięci. Łącząc te opcje konfiguracji w swoim ConfigDict, zmieniasz model z elastycznego parsera danych w absolutną, nieustępliwą granicę. To wszystko w tym odcinku. Dzięki za wysłuchanie i kodujcie dalej!
19

Konfiguracja aplikacji z Pydantic Settings

4m 00s

Zarządzaj zmiennymi środowiskowymi jak profesjonalista. Dowiesz się, jak pakiet pydantic-settings automatyzuje parsowanie sekretów, plików dot-env i prefiksów.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 19 z 20. Przestań wyciągać stringi z systemu operacyjnego i trzymać kciuki, że bez problemu castują się na integery. Prawdopodobnie napisałeś dziesiątki plików utility wrapujących standardowe wywołania zmiennych środowiskowych, tylko po to, by brakująca wartość konfiguracyjna nie wywaliła twojej aplikacji podczas runtime'u. Konfiguracja aplikacji za pomocą Pydantic Settings zastępuje cały ten boilerplate. Podczas gdy standardowy Pydantic obsługuje ogólną walidację danych, zarządzanie zmiennymi środowiskowymi wymaga zainstalowania osobnego pakietu pydantic-settings. Pakiet ten udostępnia specjalną klasę o nazwie BaseSettings. Zamiast ręcznie pobierać zmienne i pisać customową logikę parsowania, deklarujesz klasę dziedziczącą po BaseSettings. Definiujesz pola konfiguracji dokładnie tak, jak w standardowym modelu Pydantic, razem z pythonowymi type hintami i wartościami domyślnymi. Kiedy tworzysz instancję tej klasy, Pydantic automatycznie odczytuje systemowe zmienne środowiskowe. Mapuje nazwy zmiennych na atrybuty klasy, domyślnie jako case-insensitive. Jeśli zdefiniowałeś pole database timeout jako integer, a zmienna środowiskowa dostarcza string, Pydantic konwertuje ten string na rzeczywisty obiekt typu integer. Jeśli zmienna środowiskowa zawiera dowolny tekst zamiast liczby, Pydantic rzuca jasny błąd walidacji natychmiast przy starcie aplikacji. Twój program failuje od razu, zamiast nieprzewidywalnie crashować później, podczas aktywnego calla do bazy danych. W większych środowiskach nazwy zmiennych globalnych często kolidują ze sobą. Możesz mieć wiele serwisów działających na tym samym hoście, z których wszystkie szukają zmiennej o nazwie po prostu database URL. BaseSettings rozwiązuje to, pozwalając ci zdefiniować environment prefix w konfiguracji modelu. Jeśli ustawisz prefix na app underscore, Pydantic przestaje szukać dokładnych dopasowań nazw pól. Zamiast tego, aby wypełnić pole o nazwie database URL, celuje konkretnie w zmienną środowiskową app underscore database URL. Kod twojej aplikacji w Pythonie nadal odwołuje się do tego property po prostu jako database URL, całkowicie ukrywając prefix systemu operacyjnego przed twoją logiką biznesową. Oto kluczowa informacja. Nie musisz spłaszczać swoich pythonowych obiektów tylko po to, by odczytać zmienne środowiskowe. Konfiguracja często staje się złożona i wymaga zagnieżdżonych struktur danych. Możesz mieć główną klasę settings, która zawiera dedykowany sub-model dla ustawień bazy danych i kolejny dla loggingu. Pydantic wspiera resolvowanie tych zagnieżdżonych struktur za pomocą konwencji double underscore. Jeśli twoja główna klasa settings ma pole o nazwie database, które samo w sobie wskazuje na model zawierający pole timeout, Pydantic wyszuka zmienną środowiskową o nazwie database double underscore timeout. Jeśli używasz prefixu, naturalnie doda go również na początku, co da coś w stylu app underscore database double underscore timeout. Ten mechanizm pozwala ci utrzymać ściśle typowane, hierarchiczne obiekty konfiguracji w kodzie źródłowym, jednocześnie czysto mapując je na standardowe, płaskie zmienne środowiskowe. Prawdziwą wartością BaseSettings jest nie tylko eliminacja kodu boilerplate, ale gwarancja, że jeśli twoja aplikacja pomyślnie wystartuje, cały jej stan konfiguracji jest w pełni obecny, jawnie typowany i całkowicie bezpieczny do użycia. Dzięki za wysłuchanie, happy coding wszystkim!
20

Pod maską: Custom Core Schemas

3m 41s

To już ostatni odcinek serii! Przejmij całkowitą kontrolę nad silnikiem walidacji. Dowiesz się, jak napisać metodę __get_pydantic_core_schema__, aby nauczyć rdzeń w Rust, jak obsługiwać całkowicie obce obiekty Pythona.

Pobierz
Cześć, tu Alex z DEV STORIES DOT EU. Pydantic: Walidacja danych, odcinek 20 z 20. Pobierasz sztywną, nieudokumentowaną bibliotekę od innego zespołu i musisz przepuścić jej obiekty przez swój restrykcyjny pipeline walidacyjny. Obiekt nie ma absolutnie żadnego pojęcia o Pydantic, a ty nie możesz ruszyć jego kodu źródłowego. Kiedy adnotacje i proste walidatory to za mało, musisz dogadać się bezpośrednio z silnikiem — a to oznacza zajrzenie pod maskę, żeby napisać własne core schemas. Zazwyczaj Pydantic sam ogarnia, jak walidować twoje dane, czytając type hints. Kiedy wrzucasz mu obcy obiekt, uderza w mur. Żeby to naprawić, definiujesz metodę o nazwie dunder get pydantic core schema. Ta metoda działa jak bezpośrednia warstwa tłumacząca. Omija wysokopoziomowe wrappery w Pythonie i ładuje instrukcje prosto do Pydantic Core, czyli silnika w Rust, który pod spodem ogarnia właściwą logikę walidacji. Kiedy implementujesz tę metodę, przyjmuje ona typ źródłowy i handler. Handler działa dokładnie tak samo jak middleware w web frameworku. Nie musisz pisać całego schematu walidacji od zera. Możesz poprosić handler o wygenerowanie domyślnego schematu dla konkretnego typu, a potem obudować ten wynik własną logiką. Weźmy jako przykład legacy wrapper do połączenia z bazą danych. Załóżmy, że jedynym sposobem na zainicjowanie tego obiektu jest przekazanie mu konkretnego integera, na przykład ID połączenia. Chcesz, żeby Pydantic przyjął integer z requestu do API, zwalidował go i oddał ci w pełni zainicjalizowany obiekt połączenia. Ponieważ nie możesz bezpośrednio modyfikować klasy legacy, definiujesz własny typ, używając adnotacji w Pythonie. Wewnątrz tej adnotacji przekazujesz swoją własną metodę core schema. Oto kluczowa sprawa. Zamiast pisać surowe słowniki, używasz modułu core schema z Pydantic, który dostarcza funkcje pomocnicze do bezpiecznego budowania tych struktur. Najpierw prosisz handler o zbudowanie standardowego schematu dla integera. Następnie budujesz chain schema. Instruujesz silnik, żeby najpierw odpalił standardową walidację integera. Jeśli input to faktycznie integer, silnik przekazuje go do twojej własnej funkcji w Pythonie. Ta funkcja przyjmuje ID połączenia, inicjalizuje legacy wrapper bazy danych i zwraca obiekt. Na koniec dorzucasz do chaina instance check schema, żeby upewnić się, że końcowy output to dokładnie ta klasa legacy, której oczekujesz. I tu robi się ciekawie. Zwracasz tę zagnieżdżoną strukturę do Pydantic. Pod spodem Pydantic bierze te zagnieżdżone definicje słownikowe i kompiluje je do natywnego grafu wykonania w Rust. Zaprogramowałeś silnik w Rust z poziomu Pythona, mówiąc mu krok po kroku, jak przyjąć surowego integera, zwalidować go i bezpiecznie skonstruować obcy obiekt z maksymalną prędkością. To absolutnie najniższy poziom integracji, jaki oferuje Pydantic, dający ci pełną kontrolę nad drzewem walidacji bez poświęcania wydajności. Ponieważ to nasz ostatni odcinek, gorąco zachęcam cię do zanurkowania w oficjalnej dokumentacji Pydantic i spróbowania własnoręcznie zbudować własny core schema. To najlepszy sposób, żeby utrwalić sobie, jak ten silnik faktycznie myśli. Możesz też odwiedzić dev stories dot eu, żeby zasugerować tematy, o których chciałbyś usłyszeć w przyszłych seriach. To wszystko na dziś. Dzięki za słuchanie — idź zbudować coś fajnego.