Skip to main content

Data-Modeling-Pydantic

Data Modeling (Pydantic)

Topic cover:

  • Request Body
  • Pydantic BaseModel
  • Advanced Validation
  • Nested Models (Body)
  • response_model to filter output

1. Introduction & Setup (15 min)

Objectives

  • Set up a FastAPI project environment.
  • Understand what Pydantic and FastAPI do for data validation.

Content

Overview:

  • FastAPI is a high-performance web framework for building APIs with Python 3.7+.
  • It automatically handles data parsing, validation, and documentation using Pydantic and OpenAPI.

Setup Instructions

# Create and activate a virtual environment
python -m venv venv
source venv/bin/activate # (Windows: venv\Scripts\activate)

# Install dependencies
pip install fastapi uvicorn

Starter App

# main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
return {"message": "Hello, FastAPI!"}

Run the server:

uvicorn main:app --reload

Exercise (5 min)


2. Request Body (30 min)

Objectives

  • Learn how to handle incoming JSON request bodies.
  • Understand FastAPI’s automatic request parsing.

Content

Example: Handling a Simple Request Body

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None

@app.post("/items/")
async def create_item(item: Item):
return {"received": item}

What happens:

  • FastAPI reads and parses the JSON body.
  • Converts it into a Pydantic model (Item).
  • Returns structured JSON automatically.

Exercise (10 min)

Task: Create an endpoint /users/ that accepts a user object with username, email, and optional age.


3. Pydantic BaseModel (40 min)

Objectives

  • Understand how BaseModel works.
  • Learn type hints, default values, and field customization.

Key Concepts

  • Type validation: str, int, float, bool, etc.
  • Optional fields using Optional or | None.
  • Field constraints via Field.

Example: Using Field for Metadata

from pydantic import BaseModel, Field

class Product(BaseModel):
name: str = Field(..., min_length=3, max_length=50)
price: float = Field(..., gt=0)
in_stock: bool = Field(default=True)

Example Endpoint

@app.post("/products/")
async def create_product(product: Product):
return product

Exercise (15 min)

  • Create a model Book with fields:

    • title (min_length=2)
    • author
    • pages (must be > 0)
    • published (bool, default True)
  • POST /books/ → return the same data.


4. Advanced Validation (50 min)

Objectives

  • Use validators to apply custom validation logic.
  • Learn root validators and complex data checks.

Example: Field Validators

from pydantic import validator

class User(BaseModel):
username: str
password: str

@validator("password")
def password_strength(cls, v):
if len(v) < 8:
raise ValueError("Password must be at least 8 characters long")
return v

Example: Root Validators

from pydantic import root_validator

class Order(BaseModel):
price: float
quantity: int
total: float

@root_validator
def check_total(cls, values):
price, quantity, total = values.get('price'), values.get('quantity'), values.get('total')
if total != price * quantity:
raise ValueError("Total must equal price × quantity")
return values

Exercise (20 min)

  • Build a model Registration with:

    • email (must contain “@”)
    • password (min 8 chars)
    • confirm_password
  • Use a root validator to ensure passwords match.


5. Nested Models (Body) (40 min)

Objectives

  • Learn how to use nested Pydantic models for complex request bodies.
  • Understand how FastAPI automatically parses nested data.

Example: Nested Models

class Address(BaseModel):
city: str
state: str
zip_code: str

class UserProfile(BaseModel):
name: str
email: str
address: Address

@app.post("/profile/")
async def create_profile(profile: UserProfile):
return profile

Exercise (20 min)

  • Create a nested model for an Order:

    • Customer (name, email)
    • Item (name, price, quantity)
    • Order (customer: Customer, items: List[Item])
  • POST /orders/ → Return total order amount.


6. Using response_model to Filter Output (40 min)

Objectives

  • Use response_model to structure or filter API responses.
  • Hide sensitive fields such as passwords.

Example

class UserIn(BaseModel):
username: str
password: str
email: str

class UserOut(BaseModel):
username: str
email: str

@app.post("/users/", response_model=UserOut)
async def create_user(user: UserIn):
# Simulate saving user to DB
return user

What happens:

  • The request accepts all fields from UserIn.
  • The response only returns fields from UserOut.

Exercise (15 min)

  • Create:

    • UserIn: includes password
    • UserOut: excludes password
  • POST /users/register → returns safe public data.


7. Recap Practice (30 min)

Summary

  • FastAPI automatically validates request bodies.
  • Pydantic models enforce structure and constraints.
  • Validators allow for custom logic.
  • Nested models handle complex payloads.
  • response_model protects and structures output.

Final Challenge (Optional)

Build a small API for a Library System:

  • Book, Author, and Publisher models.
  • POST /books/ with nested models.
  • Use response_model to hide internal IDs.

📚 Additional Resources