D

Dynamic Pydantic Model Patterns Framework

A comprehensive skill that enables aPI schema design with Pydantic models. Built for Claude Code with best practices and real-world patterns.

SkillCommunitydevelopmentv1.0.0MIT
0 views0 copies

Pydantic Model Patterns Framework

Advanced Pydantic v2 modeling toolkit covering data validation, serialization, custom types, nested models, discriminated unions, and API schema generation for type-safe Python applications.

When to Use This Skill

Choose Pydantic Model Patterns when:

  • Building data validation layers for APIs (FastAPI, Flask)
  • Defining complex data models with nested structures
  • Creating configuration management with validation
  • Implementing serialization/deserialization pipelines
  • Generating JSON Schema or OpenAPI specs from models

Consider alternatives when:

  • Need ORM models — use SQLAlchemy or Tortoise ORM
  • Simple data classes — use stdlib dataclasses for basic structures
  • Need MongoDB schemas — use Beanie or Motor with Pydantic

Quick Start

# Activate Pydantic patterns claude skill activate dynamic-pydantic-model-patterns-framework # Design models claude "Create Pydantic models for an e-commerce order system" # Validate and transform claude "Add custom validation to the User model for email and password"

Example: Production Pydantic Models

from pydantic import BaseModel, Field, field_validator, model_validator, ConfigDict from datetime import datetime from enum import Enum from typing import Annotated class OrderStatus(str, Enum): PENDING = "pending" CONFIRMED = "confirmed" SHIPPED = "shipped" DELIVERED = "delivered" class Address(BaseModel): model_config = ConfigDict(str_strip_whitespace=True) street: str = Field(min_length=5, max_length=200) city: str = Field(min_length=2, max_length=100) state: str = Field(pattern=r'^[A-Z]{2}$') zip_code: str = Field(pattern=r'^\d{5}(-\d{4})?$') country: str = Field(default="US", pattern=r'^[A-Z]{2}$') class OrderItem(BaseModel): product_id: str quantity: int = Field(gt=0, le=100) unit_price: Annotated[float, Field(gt=0, decimal_places=2)] discount: float = Field(default=0, ge=0, le=1) @property def total(self) -> float: return round(self.quantity * self.unit_price * (1 - self.discount), 2) class Order(BaseModel): model_config = ConfigDict( str_strip_whitespace=True, validate_assignment=True, json_schema_extra={"examples": [{"customer_email": "[email protected]"}]}, ) id: str | None = None customer_email: str = Field(pattern=r'^[\w.-]+@[\w.-]+\.\w+$') items: list[OrderItem] = Field(min_length=1) shipping_address: Address status: OrderStatus = OrderStatus.PENDING created_at: datetime = Field(default_factory=datetime.utcnow) notes: str | None = Field(default=None, max_length=500) @field_validator('customer_email') @classmethod def normalize_email(cls, v: str) -> str: return v.lower() @model_validator(mode='after') def validate_order(self) -> 'Order': if self.total > 10000 and not self.notes: raise ValueError("Orders over $10,000 require notes") return self @property def total(self) -> float: return sum(item.total for item in self.items)

Core Concepts

Pydantic v2 Features

FeatureDescriptionExample
Field ValidationDeclarative constraints on fieldsField(gt=0, max_length=100)
Custom Validators@field_validator and @model_validatorComplex business logic validation
Discriminated UnionsType-safe union types with discriminator fieldAnnotated[Cat | Dog, Field(discriminator='type')]
Computed FieldsCached computed properties@computed_field
SerializationCustom JSON serialization with model_dumpmodel_dump(exclude_none=True)
Generic ModelsType-parameterized modelsclass Response(BaseModel, Generic[T])
Strict ModeDisable type coercionConfigDict(strict=True)

Model Design Patterns

PatternUse CaseExample
Input/Output ModelsDifferent shapes for create vs readUserCreate / UserResponse
Base + VariantsShared fields with specializationBaseConfigDevConfig, ProdConfig
Discriminated UnionsPolymorphic typesPayment = CreditCard | BankTransfer
Nested ModelsComplex hierarchical dataOrderOrderItemProduct
Partial ModelsOptional update schemasAll fields Optional for PATCH requests
Config ModelsApplication configurationSettings(BaseSettings) with env vars
# Discriminated Union pattern from typing import Literal, Annotated, Union from pydantic import BaseModel, Field class CreditCardPayment(BaseModel): type: Literal["credit_card"] = "credit_card" card_number: str = Field(pattern=r'^\d{16}$') expiry: str = Field(pattern=r'^\d{2}/\d{2}$') cvv: str = Field(pattern=r'^\d{3,4}$') class BankTransferPayment(BaseModel): type: Literal["bank_transfer"] = "bank_transfer" account_number: str routing_number: str = Field(pattern=r'^\d{9}$') Payment = Annotated[ Union[CreditCardPayment, BankTransferPayment], Field(discriminator='type') ] class Checkout(BaseModel): order_id: str payment: Payment # Automatically validates based on 'type' field

Configuration

ParameterDescriptionDefault
strict_modeDisable automatic type coercionfalse
validate_assignmentRe-validate when attributes changetrue
str_strip_whitespaceStrip whitespace from stringstrue
frozenMake models immutablefalse
json_schema_modeSchema generation: validation, serializationvalidation
populate_by_nameAllow field population by alias or nametrue

Best Practices

  1. Create separate models for input and output — Define UserCreate (no id, required fields) and UserResponse (includes id, computed fields, excludes password). This prevents accidentally exposing internal fields and allows different validation for creation versus display.

  2. Use Annotated types for reusable field constraints — Define Email = Annotated[str, Field(pattern=r'^[\w.-]+@[\w.-]+\.\w+$')] once and reuse across models. This centralizes validation rules and ensures consistency.

  3. Prefer model_validator(mode='after') for cross-field validation — After-mode validators receive the fully constructed model, making it easy to validate relationships between fields. Before-mode validators receive raw data and are harder to type safely.

  4. Use ConfigDict instead of inner class Config — Pydantic v2 uses model_config = ConfigDict(...) as the modern configuration approach. The inner class Config is deprecated and may be removed in future versions.

  5. Generate JSON Schema for API documentation — Use model.model_json_schema() to generate JSON Schema from your models. This integrates automatically with FastAPI's OpenAPI docs and can be exported for external API documentation.

Common Issues

Pydantic v1 code breaks when upgrading to v2. Key changes: validatorfield_validator, root_validatormodel_validator, .dict().model_dump(), .json().model_dump_json(), class Configmodel_config = ConfigDict(). Use pydantic.v1 compatibility module for gradual migration.

Validation error messages are not user-friendly for API responses. Pydantic's default ValidationError includes internal field paths and type names. Create a custom exception handler that transforms errors into user-friendly messages with the field name, constraint violated, and expected format.

Complex nested models are slow to validate for large payloads. Pydantic v2's Rust core is already 5-50x faster than v1. For extreme cases, use model_validate with strict=True to skip coercion, define __slots__ models, or validate only the fields that changed using partial validation patterns.

Community

Reviews

Write a review

No reviews yet. Be the first to review this template!

Similar Templates