Here's a self-contained, minimal, reproducible, example with my use case:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"Hello": "World"}
# sqlalchemy models
class User(Base):
__tablename__ = "user"
id = Column( Integer, primary_key=True, index=True)
full_name = Column( String, index=True)
email = Column( String, unique=True, index=True)
hashed_password = Column( String)
is_active = Column( Boolean(), default=False)
is_superuser = Column( Boolean(), default=False)
items = relationship("Item", back_populates="owner")
class Item(Base):
__tablename__ = "items"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String, index=True)
owner_id = Column(Integer, ForeignKey("user.id"))
owner = relationship("User", back_populates="items")
# pydantic models
class UserBase(BaseModel):
email: Optional[str] = None
full_name: Optional[str] = None
items: Optional[List[ItemInDBBase]]
class ItemBase(BaseModel):
title: str = None
description: str = None
owner_id: int
class ItemInDBBase(ItemBase):
id: int
title: str
owner_id: int
the frontend expects the fastapi to return the data in following format.
"users": {
"id": 5,
"full_name": "XYZ",
"email": "[email protected]",
"items": [1, 2]
}
How can I return the id's of item as a list rather than returning the item model
Assuming you follow the recommended structure:
from typing import List
from fastapi import FastAPI, Depends
from sqlalchemy import Session
from app.database import get_session
from app.models import User
app = FastAPI()
@app.get("/items", response_model=List[int])
def list_items(session: Session = Depends(get_session)):
return session.query(User.id).distinct()
In your example, just adding the endpoint itself is fine.
Something like this would fit closer, I think.
class UserBase(BaseModel):
email: Optional[str] = None
full_name: Optional[str] = None
items: Optional[List[int]]
class Config:
orm_mode = True
class getter_dict():
def __init__(self, item):
self.item = item
def get(self, name, default=None):
value = getattr(self.item, name, default)
if isinstance(value, list):
return [item.id for item in value]
else:
return value
@app.get("/", response_model=UserBase)
async def read_root():
return User(items=[Item(id=10)])
I completely missunderstood the question. What @Mause said makes more sense.
Thanks. This was extremely helpful as I am just getting started with fastapi
@Mause Do you have a complete example? I was not able to reproduce your example...
I was able to do it with validators, but not with getter_dict.
Here is a full example:
from fastapi import FastAPI
from typing import Optional, List
from pydantic import BaseModel
from sqlalchemy import Column, Integer, String, Boolean, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
app = FastAPI()
# sqlalchemy models
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True, index=True)
full_name = Column(String, index=True)
email = Column(String, unique=True, index=True)
hashed_password = Column(String)
is_active = Column(Boolean(), default=False)
is_superuser = Column(Boolean(), default=False)
items = relationship("Item", back_populates="owner")
class Item(Base):
__tablename__ = "items"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String, index=True)
owner_id = Column(Integer, ForeignKey("user.id"))
owner = relationship("User", back_populates="items")
# pydantic models
class UserBase(BaseModel):
email: Optional[str] = None
full_name: Optional[str] = None
items: Optional[List[int]]
class Config:
orm_mode = True
class getter_dict():
def __init__(self, item):
self.item = item
def get(self, name, default=None):
value = getattr(self.item, name, default)
if isinstance(value, list):
return [item.id for item in value]
else:
return value
class ItemBase(BaseModel):
title: Optional[str] = None
description: Optional[str] = None
owner_id: int
class ItemInDBBase(ItemBase):
id: int
title: str
owner_id: int
@app.get("/", response_model=UserBase)
async def read_root():
return User(items=[Item(id=10)])
from fastapi.testclient import TestClient
tc = TestClient(app)
print(tc.get('/').json())
Thank you! You made me realize what I was doing wrong :)