Skip to main content

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:

python
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:

  • UserBase defines the common fields that all user-related models will have
  • UserCreate extends UserBase and adds a password field for user creation
  • UserResponse extends UserBase and adds an ID and optional username for API responses

Using these models in a FastAPI route would look like this:

python
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:

python
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:

python
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:

python
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:

python
@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:

python
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:

python
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:

  1. Code Reuse: Define common fields and behaviors once
  2. Clear API Documentation: Create specific models for different API operations
  3. Flexibility: Override and extend models as needed
  4. 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

  1. Create a hierarchy of models for an e-commerce system with products, categories, and orders
  2. Implement a blog API with models for posts, comments, and users using inheritance
  3. Extend the user models in this tutorial to include address information and profile settings

Additional Resources



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)