Describe the bug
I have simple user creation method:
def create(self, login: str, password: str) -> models.User:
if not password:
raise RuntimeError('Password is empty')
password = utils.generate_password_hash(password)
user = models.User(login=login, password=password)
session = self.session()
session.add(user)
session.commit()
session.refresh(user)
return user
and the model:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
login = Column(String(256))
password = Column(String(1000))
created_at = Column(DateTime, default=datetime.datetime.now)
updated_at = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
removed_at = Column(DateTime, nullable=True)
and this endpoint:
@router.post('/users', status_code=HTTP_201_CREATED, response_model=schemas.UserOut)
def create_user(
user_data: schemas.UserIn,
res: UsersResource = Depends(get_users_res)
):
user = res.create(user_data.login, user_data.password.get_secret_value())
return user
with schemas:
class UserIn(BaseModel):
login: str = Schema(..., min_length=3)
password: SecretStr = Schema(..., min_length=5)
class UserOut(BaseModel):
id: int
login: str
created_at: datetime.datetime
updated_at: datetime.datetime
removed_at: Optional[datetime.datetime]
When I try to make a request it falls with the following error:
core_1 | email-validator not installed, email fields will be treated as str.
core_1 | To install, run: pip install email-validator
core_1 | INFO: Started server process [1]
core_1 | INFO: Waiting for application startup.
core_1 | INFO: Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
core_1 | INFO: ('172.21.0.1', 44266) - "POST /api/v1/users HTTP/1.1" 500
core_1 | ERROR: Exception in ASGI application
core_1 | Traceback (most recent call last):
core_1 | File "/usr/local/lib/python3.7/site-packages/uvicorn/protocols/http/httptools_impl.py", line 370, in run_asgi
core_1 | result = await app(self.scope, self.receive, self.send)
core_1 | File "/usr/local/lib/python3.7/site-packages/uvicorn/middleware/proxy_headers.py", line 37, in __call__
core_1 | await self.app(scope, receive, send)
core_1 | File "/usr/local/lib/python3.7/site-packages/starlette/applications.py", line 133, in __call__
core_1 | await self.error_middleware(scope, receive, send)
core_1 | File "/usr/local/lib/python3.7/site-packages/starlette/middleware/errors.py", line 122, in __call__
core_1 | raise exc from None
core_1 | File "/usr/local/lib/python3.7/site-packages/starlette/middleware/errors.py", line 100, in __call__
core_1 | await self.app(scope, receive, _send)
core_1 | File "/usr/local/lib/python3.7/site-packages/starlette/exceptions.py", line 73, in __call__
core_1 | raise exc from None
core_1 | File "/usr/local/lib/python3.7/site-packages/starlette/exceptions.py", line 62, in __call__
core_1 | await self.app(scope, receive, sender)
core_1 | File "/usr/local/lib/python3.7/site-packages/starlette/routing.py", line 585, in __call__
core_1 | await route(scope, receive, send)
core_1 | File "/usr/local/lib/python3.7/site-packages/starlette/routing.py", line 207, in __call__
core_1 | await self.app(scope, receive, send)
core_1 | File "/usr/local/lib/python3.7/site-packages/starlette/routing.py", line 40, in app
core_1 | response = await func(request)
core_1 | File "/usr/local/lib/python3.7/site-packages/fastapi/routing.py", line 122, in app
core_1 | skip_defaults=response_model_skip_defaults,
core_1 | File "/usr/local/lib/python3.7/site-packages/fastapi/routing.py", line 54, in serialize_response
core_1 | raise ValidationError(errors)
core_1 | pydantic.error_wrappers.ValidationError: 1 validation error
core_1 | response
core_1 | value is not a valid dict (type=type_error.dict)
This happens only when the database is postgresql. When i use sqlite everything works fine.
Environment:
I'm using dirty hack now
def model2dict(row):
d = {}
for column in row.__table__.columns:
d[column.name] = getattr(row, column.name)
return d
...
...endpoint...
return model2dict(user)
it works fine.
Are you sure one of your non-nullable model fields isn't passed a null value by SQLAlchemy? I was dealing with a similar error the other day and this turned out to be the cause, although "value is not a valid dict" seems to be a generic Pydantic error.
Use the 'orm_mode' flag in the pydantic schema, it's a new thing in the latest pydantic release. See pydantic docs for details. Solved the issue for me
Use the 'orm_mode' flag in the pydantic schema, it's a new thing in the latest pydantic release. See pydantic docs for details. Solved the issue for me
@bharling You are a gentleman and a scholar! This has been driving me nuts for ever (well, hours, but time is money).
Thanks for the solution!
Thanks for the help here @sm-Fifteen, @bharling!
Thanks @deterok for reporting back and closing the issue.
Great to see I wasn't the only one.. I'd thought that orm_mode was only for actual SQLAlchemy models themselves, not just result proxies
Most helpful comment
Use the 'orm_mode' flag in the pydantic schema, it's a new thing in the latest pydantic release. See pydantic docs for details. Solved the issue for me