Build a Blog API with Authentication • Lesson 1

Data Models Deep Dive

Master Pydantic models for data validation and serialization. Create complex nested schemas for users, blog posts, and API responses.

🎯 What You'll Learn

  • Understand Pydantic BaseModel fundamentals
  • Create nested data models with relationships
  • Implement custom validators and field constraints
  • Design request/response schemas for a blog API

Data Models Deep Dive

Welcome to the Blog API tutorial! In this lesson, you'll master Pydantic models - the foundation of data validation and serialization in FastAPI.

🎯 What We're Building

You're creating the data backbone for a Blog API with Authentication that includes:

  • 👤 User management with roles and permissions
  • 📝 Blog posts with rich metadata
  • 🔐 Authentication schemas for secure access
  • 📊 Nested responses with related data

🛠️ Pydantic Fundamentals

Pydantic is Python's most powerful data validation library that provides:

  • Automatic validation based on Python type hints
  • JSON serialization/deserialization
  • Custom validators for complex business rules
  • Clear error messages when validation fails
  • IDE support with autocomplete and type checking

🏗️ Basic Model Structure

1. Simple Model

from pydantic import BaseModel

class User(BaseModel):
    name: str
    email: str
    age: int

2. Optional Fields and Defaults

from typing import Optional

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

3. Field Constraints

from pydantic import BaseModel, Field

class User(BaseModel):
    username: str = Field(..., min_length=3, max_length=20)
    email: str = Field(..., pattern=r'^[^@]+@[^@]+\.[^@]+$')
    age: int = Field(..., ge=0, le=120)  # ge = greater equal, le = less equal

🔧 Advanced Validation

Custom Validators

from pydantic import BaseModel, validator
import re

class User(BaseModel):
    username: str
    password: str
    
    @validator('password')
    def validate_password(cls, v):
        if len(v) < 8:
            raise ValueError('Password must be at least 8 characters')
        if not re.search(r'\d', v):
            raise ValueError('Password must contain a number')
        return v

Enums for Controlled Values

from enum import Enum
from pydantic import BaseModel

class UserRole(str, Enum):
    ADMIN = "admin"
    AUTHOR = "author"
    READER = "reader"

class User(BaseModel):
    role: UserRole = UserRole.READER

🔗 Nested Models and Relationships

Creating Nested Structures

class Author(BaseModel):
    id: int
    name: str
    email: str

class BlogPost(BaseModel):
    title: str
    content: str
    author: Author  # Nested model

Inheritance for Similar Models

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

class UserCreate(UserBase):
    password: str

class UserResponse(UserBase):
    id: int
    created_at: datetime

📝 Your Task Breakdown

1. UserRole Enum

Create roles for your blog platform:

  • ADMIN: Full system access
  • AUTHOR: Can create/edit posts
  • READER: Read-only access

2. User Model

Design a comprehensive user model with:

  • Validation: Username format, email validation
  • Roles: Default to READER
  • Timestamps: Track creation time
  • Status: Active/inactive users

3. BlogPost Model

Create a rich blog post model with:

  • Content validation: Minimum content length
  • Tags system: Limited number and size
  • Publishing status: Draft vs published
  • Relationships: Link to author

4. Request/Response Schemas

Design specialized schemas for:

  • UserCreate: Registration data with password
  • BlogPostResponse: Post data with nested author info

💡 Pro Tips

Field Documentation

class User(BaseModel):
    username: str = Field(..., description="Unique username for the user")
    
    class Config:
        schema_extra = {
            "example": {
                "username": "john_doe",
                "email": "john@example.com"
            }
        }

Date Handling

from datetime import datetime
from pydantic import BaseModel

class Post(BaseModel):
    created_at: datetime
    
    class Config:
        json_encoders = {
            datetime: lambda v: v.isoformat()
        }

Validation Order

Pydantic validates fields in this order:

  1. Type validation (str, int, etc.)
  2. Field constraints (min_length, etc.)
  3. Custom validators (@validator decorated methods)

🎁 What You Get

When you complete this lesson, you'll have:

  • Type-safe models with automatic validation
  • Clear API documentation (auto-generated from models)
  • Robust error handling with detailed messages
  • IDE support with autocomplete and type hints
  • JSON serialization that "just works"

🚀 Next Steps

After mastering these data models, you'll use them to:

  • Connect to databases with SQLAlchemy
  • Handle authentication with JWT tokens
  • Create API endpoints with automatic validation
  • Upload files with proper validation

Ready to build bulletproof data models? Let's code! 🔧

💡 Hint

Start with the UserRole enum using string values. For User model, use Field() for validation constraints. Remember that Pydantic validators use @validator decorator and class methods.

Ready to Practice?

Now that you understand the theory, let's put it into practice with hands-on coding!

Start Interactive Lesson