Reputation: 348
I'm trying to alter the content of a list view on FastAPI, depending on a query parameter. As the format is defined by a pydantic model, how can I customize it (or use an alternative model from within the view)?
Here's my view:
from fastapi_pagination import Page, Params, paginate
from pydantic import BaseModel
from sqlalchemy.orm import Session
class EventSerializer(BaseModel):
id: str
# ...
class EventAttendeeSerializer(BaseModel):
id: str
event: str # contains the event UUID
# ...
class Config:
orm_mode = True
@api.get("/", response_model=Page[EventAttendeeSerializer])
async def get_list(db: Session, pagination: Params = Depends(), extend: str = None):
objects = db.query(myDbModel).all()
if "event" in extend.split(","):
# return EventSerializer for each object instead of id
return paginate(objects, pagination)
At runtime, it would work like this:
GET /v1/event-attendees/
{
"items": [
{
"id": <event_attendee_id>,
"event": <event_id>,
}
],
"total": 1,
"page": 1,
"size": 50,
}
GET /v1/event-attendees/?extend=event
{
"items": [
{
"id": <event_attendee_id>,
"event": {
"id": <event_id>,
# ...
}
}
],
"total": 1,
"page": 1,
"size": 50,
}
I searched for some kind of hooks in the pydantic and FastAPI docs and source code, but did not find anything relevant. Anyone can help please?
Upvotes: 2
Views: 988
Reputation: 34045
You can decalre a response_model
using Union
(of two types) and return the model your wish if a condition is met. Since you are returning a list of objects/models, you can have response_model
declared as a List
of Union
.
from fastapi import FastAPI
from pydantic import BaseModel
from typing import List, Union
class Simple(BaseModel):
id: int
class Specific(Simple):
description: str
RESULT = {
'id': 1,
'description': 'test'
}
app = FastAPI()
@app.get('/results', response_model=List[Union[Specific, Simple]])
def get_results(specific: bool = False):
if specific:
results = [Specific(**RESULT)] * 2
else:
results = [Simple(**RESULT)] * 2
return results
Using FastAPI 0.89.0+, you can alternatively declare the return type / response_model
in the function return type annotation, for instance:
@app.get('/results')
def get_results(specific: bool = False) -> List[Union[Specific, Simple]]:
if specific:
# ...
As for using alternate serializers (as mentioned in your question), please have a look at this answer and this answer. You can read about how FastAPI serializes a return value by default in this answer.
Upvotes: 1