pythonfastapipydantic

how to design a nested dictionary input data with pydantic model?


i have a fast api and i'm trying to model my input data, as shown below. i want to define the data class such that , the colleges is a list , but optional , a person may or may not have college experience and within this list, there is a classes list which is optional. i have included a optional keyword , such that even if the input is missing these values , the call to my api doesn't fail. is this the right way to design my classes . also , is there a better/short way to design my classes in pydantic for nested model classes ? person -> colleges , then colleges have classes , a nested structure. can one define entire structure in a single class vs having to define three classes?

{
    'name': 'john',
    'Colleges': [
        {
            'name': 'Harvard',
            ...
            'Classes': [
               {
                   'level': 'graduate',
                   'grade': 'A'
               }, 
               {
                    'level': 'graduate',
                    'grade': 'B'
               }
            ]
        }
    
    ]
    
}
# Import required modules
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List

# Create a FastAPI app instance
app = FastAPI()

class Class(BaseModel):
     level: str
     grade: int

class College(BaseModel):
    name: str
    age: int
    Classes: optional[List[Class]]= None
    

class Person(BaseModel):
    
    name: str
    description: str
    Colleges: Optional[List[College]] = None


@app.post("/create/", response_model=dict)
def create(person: Person):
    //do somethign 
    return {'message': 'success'}


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)

Solution

  • Your implementation is mostly correct. While, nesting directly in one class may be possible, but it's less readable and harder to manage as your structure grows.

    One-Class Nested Approach

    It's not recommended for readability and maintainability. However, here's how it could be done:

    class Person(BaseModel):
        name: str
        description: Optional[str] = None
        colleges: Optional[List[dict]] = None
    

    This sacrifices the benefit of strong type-checking and validation provided by Pydantic's nested models. If you need to access nested properties in your API logic, you lose auto-completion and validation benefits.

    However, there are a few corrections and improvements that can make the code cleaner and more concise:

    Improved version of your code

    from fastapi import FastAPI
    from pydantic import BaseModel
    from typing import List, Optional
    
    # Create a FastAPI app instance
    app = FastAPI()
    
    # Define nested Pydantic models
    class Class(BaseModel):
        level: str
        grade: str  # Grade should be a string (e.g., 'A', 'B')
    
    class College(BaseModel):
        name: str
        age: int
        classes: Optional[List[Class]] = None  # Use lowercase for JSON-friendly field names
    
    class Person(BaseModel):
        name: str
        description: Optional[str] = None
        colleges: Optional[List[College]] = None  # Use lowercase for JSON-friendly field names
    
    @app.post("/create/", response_model=dict)
    def create(person: Person):
        # Do something with the input
        return {'message': 'success'}
    

    Changes in your code