Last time, in Response Model, we used two models for one resource: an input with a secret field and a filtered output. Real apps often need even more states of the same thing. A blog might have an input model (with the author's email), an output model (without it), and a database model (with an internal ID). Writing all those from scratch means repeating the same fields over and over. Let's not. 🤔
One base, many subclasses
Declare a base model with the shared fields, then make small subclasses that only add what is different.
from typing import Optionalfrom fastapi import FastAPIfrom pydantic import BaseModelapp = FastAPI()class BlogBase(BaseModel): title: str content: str rating: Optional[float] = Noneclass BlogIn(BlogBase): author_email: strclass BlogOut(BlogBase): passclass BlogInDB(BlogBase): internal_id: intLet's review:
BlogBaseholds the fields every version shares, declared once.BlogInaddsauthor_emailfor input.BlogInDBaddsinternal_idfor storage.BlogOutadds nothing, it is just the public shape.Change a shared field in
BlogBaseand all three update together. No copy-paste, no drift.
Moving data between models
When you need to turn one model into another, Pydantic's .model_dump() gives you a plain dict, and Python's ** unpacks it into the next model.
@app.post("/blog", response_model=BlogOut)async def create_blog(blog: BlogIn): blog_in_db = BlogInDB(**blog.model_dump(), internal_id=123) return blog_in_dbLet's review:
blog.model_dump()turns the incomingBlogIninto a dict of its data.BlogInDB(**blog.model_dump(), internal_id=123)unpacks that dict and adds the extra field, building the database version in one line.response_model=BlogOutstill filters the response, soauthor_emailandinternal_idnever reach the client.
