'FastAPI TypeError: Object of type 'ModelMetaclass' is not JSON serializable
I'm getting this error, the models migrate successfully when i run uvicorn main:app --reload
but when i tried to go to 127.0.0.1:8000/docs i got this error. I'm using Postgresql for the database
TypeError: Object of type 'ModelMetaclass' is not JSON serializable
This is my file structure
backend/main.py
backend/pydantic_models.py
backend/requirements.txt
backend/sql
backend/sql/crud.py
backend/sql/database.py
backend/sql/sql_models.py
backend/sql/__init__.py
I followed the tutorial on https://fastapi.tiangolo.com/tutorial/sql-databases/ Here is the code. main.py
from typing import List
from fastapi import FastAPI, Depends, HTTPException, status
from sqlalchemy.orm import Session
from sql import crud, database, sql_models
from pydantic_models import User, Todo, UserCreation, TodoCreation
sql_models.Base.metadata.create_all(bind=database.engine)
app = FastAPI()
def get_db():
db = database.SessionLocal()
try:
yield db
finally:
db.close()
@app.post("/users/", response_model=User)
def create_user(user=User, db: Session = Depends(get_db)):
db_user_email = crud.get_user_by_email(db, email=user.email)
db_user_name = crud.get_user
if db_user:
raise HTTPException(status_code=status.HTTP_400_BAD,
detail="Email already taken")
return crud.create_user(db=db, user=user)
@app.get("/users/", response_model=List[User])
def read_all_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
users = crud.get_all_users(db, skip=skip, limit=limit)
return users
@app.get("/users/{user_id}", response_model=User)
def read_user(user_id: int, db: Session = Depends(get_db)):
db_user = crud.get_user(db, user_id=user_id)
if db_user is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
return db_user
@app.post("/users/{user_id}/todo/", response_model=Todo)
def create_todo_list(user_id: int, todo: TodoCreation, db: Session = Depends(get_db)):
return crud.create_todo(db=db, todo=todo, user_id=user_id)
@app.get("/items/", response_model=List[Todo])
def read_todo(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
todos = crud.get_todo(db, skip=skip, limit=limit)
return todos
pydantic_models.py
from typing import List, Optional
from pydantic import BaseModel
# Todo model
class TodoBase(BaseModel):
title: str
description: Optional[str] = None
class TodoCreation(TodoBase):
pass
class Todo(TodoBase):
id: int
owner_id: int
class Config:
orm_mode = True
# User model
class UserBase(BaseModel):
username: str
email: str
class UserCreation(UserBase):
password: str
class User(UserBase):
id: int
is_active: bool
todo: List[Todo] = []
class Config:
orm_mode = True
sql.crud.py
from sqlalchemy.orm import Session
from . import sql_models
import pydantic_models
# Get single user
def get_user(db: Session, user_id: int):
return db.query(sql_models.User).filter(models.User.id == user_id).first()
def get_user_by_name(db: Session, username: str):
return db.query(sql_models.User).filter(models.User.username == username).first()
# Get user by email
def get_user_by_email(db: Session, email: str):
return db.query(sql_models.User).filter(models.User.email == email).first()
# Get all users
def get_all_users(db: Session, skip: int = 0, limit: int = 100):
return db.query(sql_models.User).offset(skip).limit(limit).all()
# Create a user
def create_user(db: Session, user: pydantic_models.UserCreation):
fake_hashed_password = user.password + "fakehash" # Hashed user's password
db_user = sql_models.User(username=user.username, email=user.email, password=fake_hashed_password)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
def get_todo(db: Session, skip: int = 0, limit: int = 100):
return db.query(sql_models.Todo).offset(skip).limit(limit).all()
def create_todo(db: Session, todo: pydantic_models.TodoCreation, user_id: int):
db_item = models.Item(**item.dict(), owner_id=user_id)
db.add(db_item)
db.commit()
db.refresh(db_item)
return db_item
sql.database.py
import os
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = os.environ["POSTGRES_LINK"]
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
sql.sql_models.py
from sql.database import Base
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
username = Column(String, unique=True, index=True)
email = Column(String, unique=True, index=True)
password = Column(String)
is_active = Column(Boolean, default=True)
todo = relationship("Todo", back_populates="owner")
class Todo(Base):
__tablename__ = "todo"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String, index=True)
owner_id = Column(Integer, ForeignKey("users.id"))
owner = relationship("User", back_populates="todo")
here is the full error
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [6844] using statreload
INFO: Started server process [2484]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: 127.0.0.1:51303 - "GET /docs HTTP/1.1" 200 OK
INFO: 127.0.0.1:51303 - "GET /openapi.json HTTP/1.1" 500 Internal Server ErrorERROR: Exception in ASGI application
Traceback (most recent call last):
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 388, in run_asgi
result = await app(self.scope, self.receive, self.send)
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 45, in __call__
return await self.app(scope, receive, send)
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\fastapi\applications.py", line 179, in __call__
await super().__call__(scope, receive, send)
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\starlette\applications.py", line 111, in __call__
await self.middleware_stack(scope, receive, send)
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\starlette\middleware\errors.py", line 181, in __call__
raise exc from None
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\starlette\middleware\errors.py", line 159, in __call__
await self.app(scope, receive, _send)
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\starlette\exceptions.py", line 82, in __call__
raise exc from None
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\starlette\exceptions.py", line 71, in __call__
await self.app(scope, receive, sender)
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\starlette\routing.py", line 566, in __call__
await route.handle(scope, receive, send)
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\starlette\routing.py", line 227, in handle
await self.app(scope, receive, send)
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\starlette\routing.py", line 41, in app
response = await func(request)
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\fastapi\applications.py", line 128, in openapi
return JSONResponse(self.openapi())
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\fastapi\applications.py", line 106, in openapi
self.openapi_schema = get_openapi(
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\fastapi\openapi\utils.py", line 348, in get_openapi
result = get_openapi_path(route=route, model_name_map=model_name_map)
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\fastapi\openapi\utils.py", line 177, in get_openapi_path
operation_parameters = get_openapi_operation_parameters(
File "c:\users\bryan\source\repos\todoapp\backend\env\lib\site-packages\fastapi\openapi\utils.py", line 95, in get_openapi_operation_parameters
"schema": field_schema(
File "pydantic\schema.py", line 184, in pydantic.schema.field_schema
File "pydantic\schema.py", line 767, in pydantic.schema.encode_default
File "pydantic\json.py", line 62, in pydantic.json.pydantic_encoder
TypeError: Object of type 'ModelMetaclass' is not JSON serializable
Solution 1:[1]
I think the problem occurred at
@app.post("/users/", response_model=User)
def create_user(user=User, db: Session = Depends(get_db)):
db_user_email = crud.get_user_by_email(db, email=user.email)
db_user_name = crud.get_user
if db_user:
raise HTTPException(status_code=status.HTTP_400_BAD,
detail="Email already taken")
return crud.create_user(db=db, user=user)
in the main.py
file.
Changing user=User
to user: User
worked fine on mine!
Solution 2:[2]
I triggered the same error message by effectively misplacing the response_model=User
in the function def instead of the decorator.
Wrong:
@app.post("/users/")
def create_user(user: User, db: Session = Depends(get_db), response_model=User):
db_user_email = crud.get_user_by_email(db, email=user.email)
Correct:
@app.post("/users/", response_model=User)
def create_user(user: User, db: Session = Depends(get_db)):
db_user_email = crud.get_user_by_email(db, email=user.email)
Solution 3:[3]
I had a similar error but it was Object of type 'type' is not JSON serializable
. At one place, I had a function def of the following kind:
@app.post("/read")
async def read_items(item_name: str = Optional[None]):
# code omitted
return
As you can guess, I had the typing in the function defined wrongly. It should have been:
@app.post("/read")
async def read_items(item_name: Optional[str] = None):
# code omitted
return
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Brothersoo |
Solution 2 | Ben Mares |
Solution 3 | arunppsg |