Direkt zum Inhalt

Pydantic: Ein Leitfaden mit praktischen Beispielen

Hier erfährst du, was Pydantic ist, wofür es verwendet wird und wie es im Vergleich zu Alternativen wie Marshmallow oder den Datenklassen von Python aussieht.
Aktualisierte 25. Juni 2025  · 12 Min. Lesezeit

Pydantic ist die beliebteste Datenvalidierungsbibliothek in Python, die Typhinweise in Validierungsregeln zur Laufzeit umwandeln kann.

Anstatt Dutzende von if isinstance() Prüfungen und benutzerdefinierten Validierungsfunktionen zu schreiben, definierst du deine Datenstruktur einmal mit der vertrauten Python-Syntax.

Pydantic kümmert sich um den Rest: Es validiert die eingehenden Daten, konvertiert die Typen, wenn nötig, und gibt klare Fehlermeldungen aus, wenn die Validierung fehlschlägt.

Betrachte diese einfache Python-Funktion mit Typ-Hinweisen und der richtigen Dokumentation:

def calculate_user_discount(age: int, is_premium_member: bool, purchase_amount: float) -> float:
   """Calculate discount percentage based on user profile and purchase amount."""
   if age >= 65:
       base_discount = 0.15
   elif is_premium_member:
       base_discount = 0.10
   else:
       base_discount = 0.05
  
   return purchase_amount * base_discount

Wenn du dir seine Signatur ansiehst, weißt du genau, welche Art von Daten er annimmt und am anderen Ende produziert. Aber kannst du dasselbe über den Endverbraucher sagen? Schließlich dienen diese Typ-Hinweise nur der Dokumentation - wenn jemand einen falschen Datentyp übergibt, stört sich der Python-Interpreter nicht daran:

# This runs without error, even though types are completely wrong!
discount = calculate_user_discount(True, 1, 5)
print(discount)  # Output: 0.5 (True becomes 1, 1 is truthy, so 5 * 0.10)

Dies ist ein klassisches Beispiel für die dynamische Typisierung in Python. Sie ermöglicht Programmierern eine schnelle Entwicklung und Freiheit, aber das hat den Preis, dass sie Probleme bei der Typvalidierung bekommen, die in der Produktion oft auftreten.

In diesem Tutorial erkläre ich dir, wie du Pydantic in der Praxis einsetzen kannst. Wir beginnen mit deinem ersten Datenmodell und gehen dann zu fortgeschrittenen Mustern über, die in Produktionssystemen verwendet werden. Du erfährst, wie du verschachtelte Datenstrukturen validierst, benutzerdefinierte Validatoren für komplexe Geschäftsregeln schreibst und Pydantic mit gängigen Frameworks wie FastAPI und SQLAlchemy integrierst.

Was ist Pydantic?

Wenn du Anwendungen entwickelst, die mit der Außenwelt interagieren, spielst du im Grunde Datenroulette. Es kann vorkommen, dass Nutzer eine Telefonnummer als String statt als Ganzzahl übermitteln, dass eine API Nullwerte zurückgibt, wo du Zahlen erwartest, oder dass eine Konfigurationsdatei Tippfehler enthält, die deine Anwendung um 3 Uhr morgens zum Absturz bringen.

Traditionelle Python-Ansätze für dieses Problem werden schnell unhandlich. Am Ende schreibst du einen Validierungscode wie diesen:

def create_user(data):
   # Manual validation nightmare
   if not isinstance(data.get('age'), int):
       raise ValueError("Age must be an integer")
   if data['age'] < 0 or data['age'] > 150:
       raise ValueError("Age must be between 0 and 150")
   if not isinstance(data.get('email'), str) or '@' not in data['email']:
       raise ValueError("Invalid email format")
   if not isinstance(data.get('is_active'), bool):
       raise ValueError("is_active must be a boolean")
  
   # Finally create the user...
   return User(data['age'], data['email'], data['is_active'])

Multipliziere dies mit jeder Datenstruktur in deiner Anwendung, und du wirst mehr Zeit damit verbringen, Validierungscode zu schreiben als Geschäftslogik.

Pydantic löst dieses Problem durch die Kombination von drei leistungsstarken Konzepten: Typ-Hinweise, Laufzeitvalidierung und automatische Serialisierung. Statt manueller Überprüfungen definierst du deine Datenstruktur einmal mit der Python-Syntax für Typ-Annotationen, und Pydantic übernimmt die gesamte Validierung automatisch:

from pydantic import BaseModel, EmailStr
from typing import Optional

class User(BaseModel):
   age: int
   email: EmailStr
   is_active: bool = True
   nickname: Optional[str] = None

# Pydantic automatically validates and converts data
user_data = {
   "age": "25",  # String gets converted to int
   "email": "john@example.com",
   "is_active": "true"  # String gets converted to bool
}

user = User(**user_data)
print(user.age)  # 25 (as integer)
print(user.model_dump())  # Clean dictionary output

Pydantics Eigenschaften

Der Ansatz von Pydantic bietet dir mehrere Vorteile. Der erste Vorteil, den du bemerken wirst, ist die Leistung - die zentrale Validierungslogik von Pydantic ist in Rust geschrieben, was sie in den meisten Fällen schneller macht als eine handgeschriebene Python-Validierung. Deine Anwendung kann Tausende von Anfragen verarbeiten, ohne dass die Validierung zu einem Engpass wird.

Pydantic ermöglicht auch die Integration mit modernen Frameworks. FastAPI, eines der am schnellsten wachsenden Web-Frameworks in Python, nutzt Pydantic-Modelle, um automatisch API-Dokumentation zu erstellen, Anfragekörper zu validieren und Antworten zu serialisieren. Wenn du ein Pydantic-Modell definierst, bekommst du die Erstellung eines OpenAPI-Schemas kostenlos:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class UserCreate(BaseModel):
   name: str
   email: EmailStr
   age: int

@app.post("/users/")
async def create_user(user: UserCreate):
   # FastAPI automatically validates the request body
   # and generates API docs from your Pydantic model
   return {"message": f"Created user {user.name}"}

Die Erstellung des JSON-Schemas erfolgt automatisch mit jedem Pydantic-Modell. Das bedeutet, dass deine Datenstrukturen selbstdokumentierend werden und du Client-Bibliotheken, Validierungsregeln für Frontend-Anwendungen oder Datenbankschemata aus derselben Quelle der Wahrheit erstellen kannst.

Pydantic vs. Datenbrillen vs. Marshmallow

Aber wann solltest du Pydantic den Alternativen vorziehen? Wenn du Pydantic mit Datenklassen vergleichst, hängt die Entscheidung von den Validierungsanforderungen ab. Pythons @dataclass eignet sich perfekt für einfache Datencontainer, bei denen du den Eingaben vertraust, aber Pydantic ist besonders gut, wenn du Validierung, Serialisierung und Integration mit Web-Frameworks brauchst:

from dataclasses import dataclass
from pydantic import BaseModel

# Dataclass: fast, simple, no validation
@dataclass
class UserDataclass:
   name: str
   age: int

# Pydantic: validation, serialization, framework integration
class UserPydantic(BaseModel):
   name: str
   age: int

Wenn du Pydantic mit Marshmallow vergleichst, fühlt sich der Typ-Hinweis-Ansatz von Pydantic für Python-Entwickler natürlicher an, während Marshmallow Schemaklassen verwendet. Pydantic bietet außerdem eine bessere Leistung und eine einfachere Integration mit modernen asynchronen Frameworks.

Pydantic eignet sich am besten, wenn du APIs erstellst, externe Daten verarbeitest, Konfigurationen verwaltest oder in anderen Szenarien, in denen Fehler bei der Datenvalidierung frühzeitig erkannt werden sollen, anstatt später mysteriöse Bugs zu verursachen. Es wandelt Laufzeitfehler in klare, umsetzbare Validierungsmeldungen um, die sowohl Entwicklern als auch Nutzern helfen zu verstehen, was falsch gelaufen ist.

Erste Schritte mit Pydantic

Im Folgenden erfährst du, wie du Pydantic in deinen Projekten einsetzen kannst, von der Installation bis zur Erstellung deiner ersten Datenmodelle.

Installation und Einrichtung

Die Einrichtung von Pydantic ist einfach, aber es gibt ein paar typische Fallstricke, über die Neulinge stolpern können. Ich führe dich durch den korrekten Installationsprozess und helfe dir, die Fehler zu vermeiden, die unnötige Fehlersuche verursachen.

Als erstes erstellst du eine virtuelle Umgebung, um deine Projektabhängigkeiten zu isolieren. Das verhindert Versionskonflikte, die später zu mysteriösen Importfehlern führen können:

# Create and activate virtual environment (works in zsh and bash)
python -m venv pydantic_env
source pydantic_env/bin/activate  # On macOS/Linux
# pydantic_env\Scripts\activate  # On Windows

Installiere nun Pydantic mit dem folgenden Befehl:

pip install pydantic

Für die E-Mail-Validierungsfunktion, die du wahrscheinlich in realen Anwendungen (und in diesem Lernprogramm) brauchst, installiere die E-Mail-Extras:

pip install "pydantic[email]"

Die Anführungszeichen um pydantic[email] sind in fast allen Terminals wichtig. Ohne sie kann es sein, dass du die Fehlermeldung "keine Treffer gefunden" erhältst.

Hinweis: Wenn du auf ModuleNotFoundError: No module named 'pydantic' stößt, überprüfe diese Punkte:

  1. Falsche Python-Umgebung: Stelle sicher, dass deine virtuelle Umgebung aktiviert ist
  2. Mehrere Python-Versionen: Überprüfe, ob du dieselbe Python-Version verwendest, mit der du Pydantic installiert hast
  3. IDE-Konfiguration: Dein Code-Editor verwendet möglicherweise einen anderen Python-Interpreter

Kritische Benennungswarnung: Benenne deine Python-Datei niemals pydantic.py. Dadurch entsteht ein zirkulärer Import, der deinen Code mit verwirrenden Fehlermeldungen kaputt macht. Python wird versuchen, deine Datei anstelle der eigentlichen Pydantic-Bibliothek zu importieren.

Dein erstes Pydantic-Modell

Lass uns ein einfaches Benutzermodell erstellen, um Pydantic in Aktion zu sehen. Anstatt mit abstrakten Beispielen zu beginnen, werden wir ein echtes Problem lösen: die Validierung von Benutzerregistrierungsdaten aus einem Webformular.

from pydantic import BaseModel, EmailStr
from typing import Optional
from datetime import datetime

class User(BaseModel):
   name: str
   email: EmailStr
   age: int
   is_active: bool = True
   created_at: datetime = None

# Test with clean data
clean_data = {
   "name": "Alice Johnson",
   "email": "alice@example.com",
   "age": 28
}

user = User(**clean_data)
print(f"User created: {user.name}, Age: {user.age}")
print(f"Model output: {user.model_dump()}")

Ausgabe:

User created: Alice Johnson, Age: 28
Model output: {'name': 'Alice Johnson', 'email': 'alice@example.com', 'age': 28, 'is_active': True, 'created_at': None}

Schauen wir uns an, was in dieser Modelldefinition passiert:

  • Ein pydantisches Modell erstellen: Deine Klasse User erbt von BaseModel, wodurch sie alle Validierungs- und Serialisierungsfunktionen von Pydantic erhält. Diese Vererbung verwandelt eine normale Python-Klasse in ein Datenvalidierungswerkzeug.
  • Felddefinitionen: Jede Zeile in der Klasse definiert ein Feld mit seinem erwarteten Typ. Die name: str Syntax sagt Pydantic, dass name eine Zeichenkette sein sollte, age: int bedeutet, dass das Alter eine ganze Zahl sein sollte, und so weiter.
  • EmailStr erklärt: EmailStr ist ein spezieller Pydantic-Typ, der E-Mail-Adressen automatisch validiert. Sie stammt aus dem Paket pydantic[email], das du zuvor installiert hast, und verwendet reguläre Ausdrücke, um sicherzustellen, dass das E-Mail-Format gültig ist. Wenn jemand "not-an-email" angibt, wird Pydantic einen Validierungsfehler auslösen.
  • Standardwerte: Felder wie is_active: bool = True haben Standardwerte. Wenn du diese Felder bei der Erstellung eines Benutzers nicht angibst, verwendet Pydantic die Standardwerte. Die = None für created_at macht dieses Feld optional.
  • Modellinstanziierung: Wenn du User(**clean_data) aufrufst, packt ** dein Wörterbuch aus und übergibt jedes Schlüssel-Wert-Paar als Schlüsselwortargumente an den Modellkonstruktor.

Jetzt wollen wir die automatische Typumwandlung von Pydantic in Aktion sehen:

# Messy data that still works
messy_data = {
   "name": "Bob Smith",
   "email": "bob@company.com",
   "age": "35",  # String instead of int
   "is_active": "true"  # String instead of bool
}

user = User(**messy_data)
print(f"Age type: {type(user.age)}")  # <class 'int'>
print(f"Is active type: {type(user.is_active)}")  # <class 'bool'>

Jetzt wollen wir die automatische Typumwandlung von Pydantic in Aktion sehen:

# Messy data that still works
messy_data = {
   "name": "Bob Smith",
   "email": "bob@company.com",
   "age": "35",  # String instead of int
   "is_active": "true"  # String instead of bool
}

user = User(**messy_data)
print(f"Age type: {type(user.age)}")  # <class 'int'>
print(f"Is active type: {type(user.is_active)}")  # <class 'bool'>

Ausgabe:

Age type: <class 'int'>

Is active type: <class 'bool'>

Wie du siehst, werden die Felder age und is_inactive durch die Validierung automatisch in ihr richtiges Format umgewandelt.

Wenn die Validierung fehlschlägt, gibt Pydantic klare Fehlermeldungen aus:

from pydantic import ValidationError

try:
   invalid_user = User(
       name="",  # Empty string
       email="not-an-email",  # Invalid email
       age=-5  # Negative age
   )
except ValidationError as e:
   print(e)

Ausgabe:

   # Shows exactly which fields failed and why
1 validation error for User
email
 value is not a valid email address: An email address must have an @-sign. [type=value_error, input_value='not-an-email', input_type=str]

BaseModel vs. Datenklassen

Wenn du weißt, wann du die BaseModel von Pydantic und wann du die @dataclass von Python verwenden solltest, kannst du das richtige Werkzeug für jede Situation wählen.

Python-Datenklassen sind ideal für einfache Datencontainer, bei denen du die Eingabe kontrollierst:

from dataclasses import dataclass

@dataclass
class ProductDataclass:
   name: str
   price: float
   in_stock: bool

# Fast, simple, but no validation
product = ProductDataclass("Laptop", 999.99, True)

# This also works, even though types are wrong:
broken_product = ProductDataclass(123, "expensive", "maybe")

Pydantische Modelle ermöglichen Validierung, Serialisierung und Framework-Integration:

from pydantic import BaseModel, Field

class ProductPydantic(BaseModel):
   name: str = Field(min_length=1)
   price: float = Field(gt=0)  # Must be greater than 0
   in_stock: bool

# Automatic validation prevents bad data
try:
   product = ProductPydantic(name="", price=-10, in_stock="maybe")
except ValidationError as e:
   print("Validation caught the errors!")

# Valid data works perfectly
good_product = ProductPydantic(
   name="Laptop",
   price="999.99",  # String converted to float
   in_stock=True
)

Wann sollte man welchen Ansatz wählen?

  • Verwenden Sie Datenklassen für interne Datenstrukturen, Konfigurationsobjekte, oder wenn die Leistung entscheidend ist und du deinen Datenquellen vertraust
  • Verwenden Sie Pydantic für API-Endpunkte, Benutzereingaben, das Parsen externer Daten oder wenn du JSON-Serialisierung brauchst

Pydantic verursacht im Vergleich zu Datenklassen einen gewissen Mehraufwand, aber diese Kosten sind in der Regel vernachlässigbar im Vergleich zu den Fehlern, die es verhindert, und der Entwicklungszeit, die es spart. Für Webanwendungen macht die automatische Integration mit Frameworks wie FastAPI Pydantic zur klaren Wahl.

Die Validierungs- und Serialisierungsfunktionen werden immer wertvoller, je größer deine Anwendung wird. Wenn du mit den Modellen von Pydantic beginnst, hast du eine solide Grundlage, die sich an deine Bedürfnisse anpassen lässt.

Datenmodelle mit Pydantic erstellen

Jetzt, wo du die Grundlagen kennst, können wir die Herausforderungen angehen, denen du bei der Erstellung produktionsreifer Anwendungen begegnen wirst.

Feldvalidierung und Beschränkungen

Betrachte eine Produktkatalog-API, bei der die Preisdaten von mehreren Anbietern mit unterschiedlichen Formatierungsstandards stammen. Manche senden Preise als Strings, andere als Floats, und gelegentlich sendet jemand einen negativen Preis, der dein Abrechnungssystem zum Absturz bringt.

Die Funktion Field() von Pydantic verwandelt einfache Typ-Hinweise in ausgefeilte Validierungsregeln, die deine Anwendung schützen:

from pydantic import BaseModel, Field
from decimal import Decimal
from typing import Optional

class Product(BaseModel):
   name: str = Field(min_length=1, max_length=100)
   price: Decimal = Field(gt=0, le=10000)  # Greater than 0, less than or equal to 10,000
   description: Optional[str] = Field(None, max_length=500)
   category: str = Field(..., pattern=r'^[A-Za-z\s]+$')  # Only letters and spaces
   stock_quantity: int = Field(ge=0)  # Greater than or equal to 0
   is_available: bool = True

# This works - all constraints satisfied
valid_product = Product(
   name="Wireless Headphones",
   price="199.99",  # String converted to Decimal
   description="High-quality wireless headphones",
   category="Electronics",
   stock_quantity=50
)

# This fails with clear error messages
try:
   invalid_product = Product(
       name="",  # Too short
       price=-50,  # Negative price
       category="Electronics123",  # Contains numbers
       stock_quantity=-5  # Negative stock
   )
except ValidationError as e:
   print(f"Validation errors: {len(e.errors())} issues found")

Jeder Field() Parameter dient einem bestimmten Zweck: min_length und max_length verhindern Verletzungen des Datenbankschemas, gt und le schaffen Grenzen für die Geschäftslogik und pattern validiert formatierte Daten mithilfe regulärer Ausdrücke. Die Field(...) Syntax mit Ellipsen markiert die Pflichtfelder, während Field(None, ...) optionale Felder mit Validierungsregeln erstellt.

Typenzwang vs. strenge Validierung

Standardmäßig wandelt Pydantic kompatible Typen um, anstatt sie komplett abzulehnen. Diese Flexibilität eignet sich gut für Benutzereingaben, aber es gibt auch Szenarien, die eine exakte Typenzuordnung erfordern:

from pydantic import BaseModel, Field, ValidationError

# Default: lenient type coercion
class FlexibleOrder(BaseModel):
   order_id: int
   total_amount: float
   is_paid: bool

# These all work due to automatic conversion
flexible_order = FlexibleOrder(
   order_id="12345",  # String to int
   total_amount="99.99",  # String to float
   is_paid="true"  # String to bool
)

# Strict validation when precision matters
class StrictOrder(BaseModel):
   model_config = {"str_strip_whitespace": True, "validate_assignment": True}
  
   order_id: int = Field(strict=True)
   total_amount: float = Field(strict=True)
   is_paid: bool = Field(strict=True)

Das model_config Wörterbuch steuert das Validierungsverhalten in deinem gesamten Modell. Die Option str_strip_whitespace bereinigt String-Eingaben automatisch, während validate_assignment sicherstellt, dass Feldänderungen nach der Modellerstellung weiterhin eine Validierung auslösen. Einzelne Felder können diese Einstellungen mit Field(strict=True) außer Kraft setzen, wenn eine exakte Typenzuordnung erforderlich ist, z. B. bei finanziellen Berechnungen oder wissenschaftlichen Daten.

Verschachtelte Modelle und komplexe Daten

Echte Anwendungen arbeiten mit komplexen, vernetzten Datenstrukturen. Eine E-Commerce-Bestellung enthält Kundeninformationen, Lieferadressen und mehrere Produktartikel, die jeweils eine eigene Validierung erfordern:

from typing import List
from datetime import datetime

class Address(BaseModel):
   street: str = Field(min_length=5)
   city: str = Field(min_length=2)
   postal_code: str = Field(pattern=r'^\d{5}(-\d{4})?$')
   country: str = "USA"

class Customer(BaseModel):
   name: str = Field(min_length=1)
   email: EmailStr
   shipping_address: Address
   billing_address: Optional[Address] = None

class OrderItem(BaseModel):
   product_id: int = Field(gt=0)
   quantity: int = Field(gt=0, le=100)
   unit_price: Decimal = Field(gt=0)

class Order(BaseModel):
   order_id: str = Field(pattern=r'^ORD-\d{6}$')
   customer: Customer
   items: List[OrderItem] = Field(min_items=1)
   order_date: datetime = Field(default_factory=datetime.now)

# Complex nested data validation
order_data = {
   "order_id": "ORD-123456",
   "customer": {
       "name": "John Doe",
       "email": "john@example.com",
       "shipping_address": {
           "street": "123 Main Street",
           "city": "Anytown",
           "postal_code": "12345"
       }
   },
   "items": [
       {"product_id": 1, "quantity": 2, "unit_price": "29.99"},
       {"product_id": 2, "quantity": 1, "unit_price": "149.99"}
   ]
}

order = Order(**order_data)
print(f"Order validated with {len(order.items)} items")

Pydantic validiert verschachtelte Strukturen rekursiv - das Feld Customer wird zu einem vollständigen Customer Objekt, das sein eigenes Feld Address validiert. Die List[OrderItem] Syntax validiert jedes Listenelement als OrderItem, während Field(min_items=1) verhindert, dass leere Bestellungen dein Bestandssystem erreichen. Mit default_factory=datetime.now werden eindeutige Zeitstempel für jede Bestellinstanz erstellt.

Optionale Felder und Keine Behandlung

Verschiedene Vorgänge benötigen unterschiedliche Datenanforderungen. Bei der Erstellung eines Benutzers müssen die Informationen vollständig sein, während bei der Aktualisierung auch Teiländerungen akzeptiert werden sollten:

from typing import Optional

class UserCreate(BaseModel):
   name: str = Field(min_length=1)
   email: EmailStr
   age: int = Field(ge=13, le=120)
   phone: Optional[str] = Field(None, pattern=r'^\+?1?\d{9,15}$')

class UserUpdate(BaseModel):
   name: Optional[str] = Field(None, min_length=1)
   email: Optional[EmailStr] = None
   age: Optional[int] = Field(None, ge=13, le=120)
   phone: Optional[str] = Field(None, pattern=r'^\+?1?\d{9,15}$')

# PATCH request with partial data
update_data = {"name": "Jane Smith", "age": 30}
user_update = UserUpdate(**update_data)

# Serialize only provided fields
patch_data = user_update.model_dump(exclude_none=True)
print(f"Fields to update: {list(patch_data.keys())}")

Die Serialisierung wandelt Pydantic-Objekte für die Speicherung oder Übertragung wieder in Wörterbücher oder JSON-Strings um. Die Methode model_dump() kümmert sich um diese Umwandlung, wobei exclude_none=True nicht bereitgestellte Felder entfernt. Dieses Muster eignet sich perfekt für PATCH-Anfragen, bei denen die Kunden nur die Felder senden, die sie ändern wollen, und verhindert so ein versehentliches Überschreiben der Daten in deiner Datenbank.

Diese Grundlage bereitet dich auf die nächste Herausforderung vor: die Implementierung einer benutzerdefinierten Validierungslogik, die die einzigartigen Geschäftsregeln deiner Anwendung erfasst.

Benutzerdefinierte Validierung und Integration in die reale Welt

Bei der Entwicklung von Produktionsanwendungen müssen Daten verarbeitet werden, die nicht in die Standard-Typenprüfungsmuster passen.

Denken Sie an ein Benutzerregistrierungsformular, bei dem die Passwortanforderungen je nach Abonnementplan variieren, oder an eine API, die Adressdaten aus mehreren Ländern mit unterschiedlichen Postleitzahlenformaten empfängt. Diese Szenarien erfordern eine benutzerdefinierte Validierungslogik, die deine spezifischen Geschäftsregeln erfasst und sich reibungslos in Web-Frameworks und Konfigurationssysteme integrieren lässt.

Dieser Abschnitt zeigt dir, wie du praktische benutzerdefinierte Validierungsmuster implementierst, Pydantic-Modelle mit FastAPI für die automatische API-Dokumentation integrierst und Anwendungseinstellungen über Umgebungsvariablen verwaltest, indem du den .env Datei-Ansatz verwendest, auf den sich die meisten Produktionsanwendungen verlassen.

Feldvalidierer und Modellvalidierung

Wenn die Geschäftslogik die Gültigkeit der Daten bestimmt, verwandelt der @field_validator Dekorator von Pydantic deine Validierungsfunktionen in einen Teil des Modells selbst. Stell dir ein System zur Benutzerregistrierung vor, bei dem die verschiedenen Abonnementstufen unterschiedliche Passwortanforderungen haben:

from pydantic import BaseModel, field_validator, Field
import re

class UserRegistration(BaseModel):
   username: str = Field(min_length=3)
   email: EmailStr
   password: str
   subscription_tier: str = Field(pattern=r'^(free|pro|enterprise)$')
  
   @field_validator('password')
   @classmethod
   def validate_password_complexity(cls, password, info):
       tier = info.data.get('subscription_tier', 'free')
      
       if len(password) < 8:
           raise ValueError('Password must be at least 8 characters')
          
       if tier == 'enterprise' and not re.search(r'[A-Z]', password):
           raise ValueError('Enterprise accounts require uppercase letters')
          
       return password

Mit dem @field_validator Dekorator kannst du über den Parameter info.data auf andere Feldwerte zugreifen und so Validierungsregeln erstellen, die von mehreren Feldern abhängen. Der Validator wird ausgeführt, nachdem die grundlegende Typüberprüfung bestanden wurde, sodass du davon ausgehen kannst, dass subscription_tier einer der zulässigen Werte ist.

Bei Überprüfungen, die sich über mehrere Felder erstrecken, wird der @model_validator Dekorator ausgeführt, nachdem alle einzelnen Felder überprüft wurden:

from datetime import datetime
from pydantic import model_validator

class EventRegistration(BaseModel):
   start_date: datetime
   end_date: datetime
   max_attendees: int = Field(gt=0)
   current_attendees: int = Field(ge=0)
  
   @model_validator(mode='after')
   def validate_event_constraints(self):
       if self.end_date <= self.start_date:
           raise ValueError('Event end date must be after start date')
          
       if self.current_attendees > self.max_attendees:
           raise ValueError('Current attendees cannot exceed maximum')
          
       return self

Der Parameter mode='after' stellt sicher, dass der Validator eine vollständig konstruierte Modellinstanz erhält, was ihn perfekt für Geschäftslogik macht, die Zugriff auf alle validierten Felder benötigt. Der Validator muss self zurückgeben, um die erfolgreiche Validierung anzuzeigen.

FastAPI-Integration

Die Integration von FastAPI in Pydantic ermöglicht eine automatische Validierung von Anfragen und eine API-Dokumentation. Das wichtigste Muster besteht darin, dass du für verschiedene Vorgänge separate Modelle erstellst, damit du die Kontrolle darüber hast, welche Daten in welche Richtung fließen:

from fastapi import FastAPI
from typing import Optional
from datetime import datetime

app = FastAPI()

class UserCreate(BaseModel):
   username: str = Field(min_length=3)
   email: EmailStr
   password: str = Field(min_length=8)

class UserResponse(BaseModel):
   id: int
   username: str
   email: EmailStr
   created_at: datetime
  
@app.post("/users/", response_model=UserResponse)
async def create_user(user: UserCreate):
   # FastAPI automatically validates the request body
   new_user = {
       "id": 1,
       "username": user.username,
       "email": user.email,
       "created_at": datetime.now()
   }
   return UserResponse(**new_user)

Die Trennung zwischen Input- und Output-Modellen bietet mehrere Vorteile. Eingabemodelle können Validierungsregeln und Pflichtfelder enthalten, während Ausgabemodelle genau steuern, welche Daten an die Kunden gesendet werden. FastAPI generiert automatisch OpenAPI-Dokumentation aus deinen Pydantic-Modellen und erstellt interaktive API-Dokumente, die Entwickler zum Testen von Endpunkten verwenden können.

Für Aktualisierungsvorgänge kannst du Modelle erstellen, bei denen alle Felder optional sind:

class UserUpdate(BaseModel):
   username: Optional[str] = Field(None, min_length=3)
   email: Optional[EmailStr] = None

@app.patch("/users/{user_id}")
async def update_user(user_id: int, user_update: UserUpdate):
   # Only update provided fields
   update_data = user_update.model_dump(exclude_unset=True)
   # Your database update logic here
   return {"message": f"Updated user {user_id}"}

Der Parameter exclude_unset=True in PATCH-Vorgängen stellt sicher, dass du nur Felder aktualisierst, die explizit angegeben wurden, um versehentliches Überschreiben zu verhindern. Dieses Muster eignet sich perfekt für REST-APIs, bei denen Kunden Teilaktualisierungen senden.

Konfigurationsmanagement mit Umgebungsvariablen

Produktionsanwendungen brauchen ein sicheres, einsatzfreundliches Konfigurationsmanagement. Pydantic's BaseSettings kombiniert mit .env Dateien bietet eine typsichere Konfiguration, die in Entwicklungs-, Staging- und Produktionsumgebungen funktioniert.

Erstelle zunächst eine .env Datei im Stammverzeichnis deines Projekts:

# .env file
DATABASE_URL=postgresql://user:password@localhost:5432/myapp
SECRET_KEY=your-secret-key-here
DEBUG=false
ALLOWED_HOSTS=localhost,127.0.0.1,yourdomain.com

Dann definiere dein Einstellungsmodell:

from pydantic import BaseSettings, Field
from typing import List

class AppSettings(BaseSettings):
   database_url: str = Field(description="Database connection URL")
   secret_key: str = Field(description="Secret key for JWT tokens")
   debug: bool = Field(default=False)
   allowed_hosts: List[str] = Field(default=["localhost"])
  
   class Config:
       env_file = ".env"
       case_sensitive = False

# Load settings automatically from environment and .env file
settings = AppSettings()

Die Klasse BaseSettings liest automatisch aus Umgebungsvariablen, .env Dateien und Kommandozeilenargumenten. Umgebungsvariablen haben Vorrang vor den Werten der .env Datei, so dass es einfach ist, die Einstellungen in verschiedenen Einsatzumgebungen außer Kraft zu setzen. Die Einstellung case_sensitive = False ermöglicht eine flexible Benennung von Umgebungsvariablen.

Für komplexe Anwendungen kannst du die Einstellungen in logischen Gruppen organisieren:

class DatabaseSettings(BaseSettings):
   url: str = Field(env="DATABASE_URL")
   max_connections: int = Field(default=5, env="DB_MAX_CONNECTIONS")

class AppSettings(BaseSettings):
   secret_key: str
   debug: bool = False
   database: DatabaseSettings = DatabaseSettings()
  
   class Config:
       env_file = ".env"

settings = AppSettings()
# Access nested configuration
db_url = settings.database.url

Dieser verschachtelte Ansatz hält zusammengehörige Einstellungen zusammen und sorgt gleichzeitig für eine klare Trennung zwischen den verschiedenen Komponenten deiner Anwendung. Jede Einstellungsgruppe kann ihr eigenes Umgebungsvariablen-Präfix und eigene Validierungsregeln haben.

Der .env Datei-Ansatz funktioniert mit Bereitstellungsplattformen wie Heroku, AWS und Docker, wo Umgebungsvariablen die Standardmethode zur Konfiguration von Anwendungen sind. Deine Anwendung erhält Typensicherheit und -validierung und folgt dabei Cloud-nativen Konfigurationsmustern, die Betriebsteams erwarten.

Diese Muster bilden die Grundlage für den Aufbau wartbarer Anwendungen, die die Komplexität der realen Welt bewältigen. Das Validierungssystem von Pydantic passt sich an deine spezifischen Anforderungen an und liefert klare Fehlermeldungen und eine automatische Dokumentation, die deinem gesamten Team hilft, die Datenstrukturen zu verstehen, die deine Anwendung erwartet.

Fazit

Du hast jetzt gesehen, wie Pydantic dir die mühsame Arbeit ersparen kann, den Validierungscode von Hand zu schreiben. Anstatt deine Funktionen mit isinstance() Überprüfungen und benutzerdefinierter Fehlerbehandlung zu überfrachten, kannst du deine Datenstruktur einmal definieren und Pydantic den Rest erledigen lassen.

Lies unbedingt den Abschnitt "Häufig gestellte Fragen" weiter unten, wenn du weitere spezifische Fragen zu Pydantic hast. Für eine umfassende Dokumentation und fortgeschrittene Muster findest du hier ein paar Ressourcen, die du nutzen kannst:

FAQs

Verlangsamt die Pydantic-Validierung meine Anwendung?

Pydantic V2 ist mit Rust unter der Haube gebaut, was es sehr schnell macht. Bei den meisten Anwendungen ist der Aufwand für die Validierung minimal im Vergleich zu den Fehlern, die dadurch verhindert werden. Du kannst model_construct() verwenden, um die Validierung für vertrauenswürdige Datenquellen zu überspringen, wenn die Leistung entscheidend ist.

Wann sollte ich Pydantic anstelle von Python-Datenklassen verwenden?

Nutze Pydantic, wenn du Validierungen brauchst, mit externen Datenquellen arbeitest oder APIs erstellst. Verwende Dataklassen für einfache interne Datenstrukturen, bei denen du der Eingabe vertraust. Pydantic eignet sich besonders gut für Daten, die von Benutzern, APIs oder Konfigurationsdateien stammen.

Wie gehe ich mit Pydantic-Validierungsfehlern in Produktionsanwendungen um?

Fange ValidationError Ausnahmen ab und extrahiere die .errors() Liste, um strukturierte Fehlerinformationen zu erhalten. Jeder Fehler enthält die Felder loc, msg und type, mit denen du benutzerfreundliche Fehlermeldungen erstellen oder detaillierte Debugging-Informationen protokollieren kannst.

Kann ich Pydantic zu bestehendem Code hinzufügen, ohne alles kaputt zu machen?

Ja! Beginne damit, externe Dateneingabepunkte (API-Anfragen, Dateiparsing) mit Pydantic-Modellen zu verpacken. Du kannst interne Datenstrukturen schrittweise umwandeln. Pydantic funktioniert neben bestehendem Code und erfordert nicht, dass du deine gesamte Codebasis auf einmal ändern musst.

Was ist der häufigste Fehler beim Start mit Pydantic?

Kein Verständnis für den Typenzwang. Pydantic wandelt kompatible Typen (wie die Zeichenkette "123" in die ganze Zahl 123) standardmäßig um. Wenn du eine strenge Typüberprüfung benötigst, verwende Field(strict=True) oder setze den strengen Modus in deiner Modellkonfiguration, um automatische Konvertierungen zu verhindern.


Bex Tuychiev's photo
Author
Bex Tuychiev
LinkedIn

Ich bin ein Data Science Content Creator mit über 2 Jahren Erfahrung und einem der größten Follower auf Medium. Ich schreibe gerne ausführliche Artikel über KI und ML mit einem etwas sarkastischen Stil, denn man muss etwas tun, damit sie nicht so langweilig sind. Ich habe mehr als 130 Artikel verfasst und einen DataCamp-Kurs gemacht, ein weiterer ist in Vorbereitung. Meine Inhalte wurden von über 5 Millionen Augenpaaren gesehen, von denen 20.000 zu Followern auf Medium und LinkedIn wurden. 

Themen

Lerne Data Science mit DataCamp!

Kurs

Software Engineering Principles in Python

4 Std.
54.2K
Learn about modularity, documentation, and automated testing to help you solve data science problems more quickly and reliably.
Siehe DetailsRight Arrow
Kurs starten
Mehr anzeigenRight Arrow
Verwandt

Der Blog

Lehrer/innen und Schüler/innen erhalten das Premium DataCamp kostenlos für ihre gesamte akademische Laufbahn

Keine Hacks, keine Tricks. Schüler/innen und Lehrer/innen, lest weiter, um zu erfahren, wie ihr die Datenerziehung, die euch zusteht, kostenlos bekommen könnt.
Nathaniel Taylor-Leach's photo

Nathaniel Taylor-Leach

4 Min.

Der Blog

Die 20 besten Snowflake-Interview-Fragen für alle Niveaus

Bist du gerade auf der Suche nach einem Job, der Snowflake nutzt? Bereite dich mit diesen 20 besten Snowflake-Interview-Fragen vor, damit du den Job bekommst!
Nisha Arya Ahmed's photo

Nisha Arya Ahmed

15 Min.

Der Blog

Top 30 Generative KI Interview Fragen und Antworten für 2024

Dieser Blog bietet eine umfassende Sammlung von Fragen und Antworten zu generativen KI-Interviews, die von grundlegenden Konzepten bis hin zu fortgeschrittenen Themen reichen.
Hesam Sheikh Hassani's photo

Hesam Sheikh Hassani

15 Min.

Der Blog

Die 50 besten AWS-Interview-Fragen und Antworten für 2025

Ein kompletter Leitfaden zur Erkundung der grundlegenden, mittleren und fortgeschrittenen AWS-Interviewfragen, zusammen mit Fragen, die auf realen Situationen basieren.
Zoumana Keita 's photo

Zoumana Keita

15 Min.

Der Blog

2022-2023 DataCamp Classrooms Jahresbericht

Zu Beginn des neuen Schuljahres ist DataCamp Classrooms motivierter denn je, das Lernen mit Daten zu demokratisieren. In den letzten 12 Monaten sind über 7.650 neue Klassenzimmer hinzugekommen.
Nathaniel Taylor-Leach's photo

Nathaniel Taylor-Leach

8 Min.

Der Blog

Q2 2023 DataCamp Donates Digest

DataCamp Donates hat im zweiten Quartal 2023 über 20.000 Stipendien an unsere gemeinnützigen Partner vergeben. Erfahre, wie fleißige benachteiligte Lernende diese Chancen in lebensverändernde berufliche Erfolge verwandelt haben.
Nathaniel Taylor-Leach's photo

Nathaniel Taylor-Leach

Mehr anzeigenMehr anzeigen