FastAPI Model Inheritance
Introduction
When building APIs with FastAPI, you'll often need to define multiple related data models. These models might share common fields or behaviors. Rather than duplicating code across models, Pydantic (FastAPI's data validation library) supports inheritance, allowing you to create base models that can be extended by other models.
In this tutorial, we'll explore how to leverage model inheritance in FastAPI to create clean, reusable, and maintainable code structures.
Understanding Pydantic Model Inheritance
Model inheritance in Pydantic works similarly to regular Python class inheritance. You can create a base model with common fields and methods, then extend it to create more specialized models.
Basic Inheritance Example
Let's start with a simple example:
from pydantic import BaseModel
from typing import Optional
# Base model with common fields
class UserBase(BaseModel):
    email: str
    is_active: bool = True
# Creating child models that inherit from UserBase
class UserCreate(UserBase):
    password: str
class UserResponse(UserBase):
    id: int
    username: Optional[str] = None
In this example:
- UserBasedefines the common fields that all user-related models will have
- UserCreateextends- UserBaseand adds a password field for user creation
- UserResponseextends- UserBaseand adds an ID and optional username for API responses
Using these models in a FastAPI route would look like this:
from fastapi import FastAPI
app = FastAPI()
@app.post("/users/", response_model=UserResponse)
def create_user(user: UserCreate):
    # In a real application, you would save to a database
    # and hash the password
    return {
        "id": 1,  # generated ID
        "email": user.email,
        "is_active": user.is_active,
        "username": None
    }
Advanced Inheritance Techniques
Config Inheritance
You can also inherit configuration settings from parent models:
class BaseModel(BaseModel):
    class Config:
        # Base configuration
        extra = "forbid"  # Reject extra fields
        orm_mode = True   # Allow ORM mode
class ChildModel(BaseModel):
    # Inherits the Config from BaseModel
    name: str
    age: int
Multiple Inheritance
Pydantic supports multiple inheritance, allowing you to combine fields and behaviors from multiple parent models:
class TimestampMixin(BaseModel):
    created_at: datetime
    updated_at: Optional[datetime] = None
class AuditMixin(BaseModel):
    created_by: str
    updated_by: Optional[str] = None
class Product(TimestampMixin, AuditMixin):
    id: int
    name: str
    price: float
    description: Optional[str] = None
Here, Product inherits fields from both TimestampMixin and AuditMixin.
Practical Use Cases
1. API Request/Response Models
One common pattern is to create a base model and then extend it for different API operations:
from typing import List, Optional
from pydantic import BaseModel
class ArticleBase(BaseModel):
    title: str
    content: str
    published: bool = False
class ArticleCreate(ArticleBase):
    # No additional fields, but we separate it for API clarity
    pass
class ArticleUpdate(BaseModel):
    title: Optional[str] = None
    content: Optional[str] = None
    published: Optional[bool] = None
class ArticleInDB(ArticleBase):
    id: int
    author_id: int
class ArticleResponse(ArticleInDB):
    tags: List[str] = []
Using these models in FastAPI routes:
@app.post("/articles/", response_model=ArticleResponse)
def create_article(article: ArticleCreate, current_user_id: int = Depends(get_current_user)):
    # Logic to create the article
    new_article = {
        **article.dict(),
        "id": generate_id(),
        "author_id": current_user_id,
        "tags": []
    }
    return new_article
@app.patch("/articles/{article_id}", response_model=ArticleResponse)
def update_article(article_id: int, article_update: ArticleUpdate):
    # Logic to update the article
    updated_article = {
        "id": article_id,
        "author_id": 1,
        "title": "Updated title" if article_update.title else "Original title",
        "content": "Updated content" if article_update.content else "Original content",
        "published": article_update.published if article_update.published is not None else False,
        "tags": ["updated"]
    }
    return updated_article
2. Database Models and DTOs
When working with databases, you can create a hierarchy of models for different purposes:
from datetime import datetime
from typing import Optional, List
from pydantic import BaseModel, EmailStr
# Base user model
class UserBase(BaseModel):
    email: EmailStr
    name: str
    is_active: bool = True
# For creating users
class UserCreate(UserBase):
    password: str
# For database storage
class UserInDB(UserBase):
    id: int
    hashed_password: str
    created_at: datetime
    
    class Config:
        orm_mode = True
# For API responses
class UserPublic(UserBase):
    id: int
    created_at: datetime
    
    class Config:
        orm_mode = True
# For including user posts
class Post(BaseModel):
    id: int
    title: str
    content: str
    
    class Config:
        orm_mode = True
class UserWithPosts(UserPublic):
    posts: List[Post] = []
Field Overriding
You can override fields from parent models in child models. This is useful when you need to change field types or add validation:
from pydantic import BaseModel, Field
class Parent(BaseModel):
    name: str
    age: int = Field(..., gt=0)
class Child(Parent):
    # Override the age field to be more restrictive
    age: int = Field(..., gt=0, lt=18)
Summary
Model inheritance in FastAPI's Pydantic models offers a powerful way to organize your data models and reduce code duplication. Key benefits include:
- Code Reuse: Define common fields and behaviors once
- Clear API Documentation: Create specific models for different API operations
- Flexibility: Override and extend models as needed
- Better Organization: Create logical hierarchies of related models
When building complex APIs, leveraging model inheritance helps maintain a clean and maintainable codebase while ensuring your data validation remains robust.
Exercises
- Create a hierarchy of models for an e-commerce system with products, categories, and orders
- Implement a blog API with models for posts, comments, and users using inheritance
- Extend the user models in this tutorial to include address information and profile settings
Additional Resources
💡 Found a typo or mistake? Click "Edit this page" to suggest a correction. Your feedback is greatly appreciated!