Skip to content

Unable to do validation on models. #46

@jymchng

Description

@jymchng

Let's supposed I have the following model and create schema.

class ProjectBase(SQLModel):
    name: str = Field(nullable=False)
    repr_name: Optional[str] = Field(default=None, nullable=False)
    is_active: bool = Field(default=True, nullable=False)
    publish_date: date = Field(
        default_factory=datetime.now().date, nullable=False)
    approved: bool = Field(default=False, nullable=False)
    featured: bool = Field(default=False, nullable=False)
    
    # post_init
    @validator("repr_name", always=True)
    def slugify_name(cls, v: Optional[str], values: dict[str, Any]) -> str:
        if v is None:
            logger.info(f"{v=}, {values=}")
            repr_name = slugify(values.get('name'), separator="_")
            return repr_name
        raise ValueError(
            f"`repr_name` cannot be passed in as a parameter to the `Request`.")

As you can see, I am trying to post-process the name field by 'slugify' it.

The ICreateProject schema is as follows:

class IProjectCreate(ProjectBase):
    pass

As I try to create a project using the API, with the following request:

curl -X 'POST' \
  'http://localhost/api/v1/project' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NzY2NTc1MzgsInN1YiI6IjAxODYzZjUwLTkyNWMtNzU3Ny1hYTdmLTc4NmQ1Mjc4M2U2YSIsInR5cGUiOiJhY2Nlc3MifQ.bOtkIl5wJl1ahzGG_A5y7Dei-jxvrmtZalglclXaiR8' \
  -H 'Content-Type: application/json' \
  -d '{
  "is_active": true,
  "name": "Hello A",
  "publish_date": "2023-02-17",
  "approved": false,
  "featured": false
}'

The error log I got is this:

2023-02-18 02:08:37 INFO:     Application startup complete.
2023-02-18 02:08:43 2023-02-17 18:08:43,325 INFO     [project_model.py:29] v=None, values={'name': 'Hello A'}
2023-02-18 02:08:43 2023-02-17 18:08:43,325 INFO     [project_model.py:29] v=None, values={'name': 'Hello A'}
2023-02-18 02:08:43 2023-02-17 18:08:43,326 INFO     [base_crud.py:159] In CRUD.create
2023-02-18 02:08:43 2023-02-17 18:08:43,326 INFO     [base_crud.py:160] obj_in=IProjectCreate(name='Hello A', repr_name='hello_a', is_active=True, publish_date=datetime.date(2023, 2, 17), approved=False, featured=False)
2023-02-18 02:08:43 2023-02-17 18:08:43,326 INFO     [project_model.py:29] v=None, values={}
2023-02-18 02:08:43 INFO:     172.18.0.3:54102 - "POST /api/v1/project HTTP/1.1" 500 Internal Server Error
2023-02-18 02:08:43 ERROR:    Exception in ASGI application
2023-02-18 02:08:43 Traceback (most recent call last):
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/anyio/streams/memory.py", line 94, in receive
2023-02-18 02:08:43     return self.receive_nowait()
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/anyio/streams/memory.py", line 89, in receive_nowait
2023-02-18 02:08:43     raise WouldBlock
2023-02-18 02:08:43 anyio.WouldBlock
2023-02-18 02:08:43 
2023-02-18 02:08:43 During handling of the above exception, another exception occurred:
2023-02-18 02:08:43 
2023-02-18 02:08:43 Traceback (most recent call last):
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/base.py", line 77, in call_next
2023-02-18 02:08:43     message = await recv_stream.receive()
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/anyio/streams/memory.py", line 114, in receive
2023-02-18 02:08:43     raise EndOfStream
2023-02-18 02:08:43 anyio.EndOfStream
2023-02-18 02:08:43 
2023-02-18 02:08:43 During handling of the above exception, another exception occurred:
2023-02-18 02:08:43 
2023-02-18 02:08:43 Traceback (most recent call last):
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
2023-02-18 02:08:43     result = await app(  # type: ignore[func-returns-value]
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
2023-02-18 02:08:43     return await self.app(scope, receive, send)
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/fastapi/applications.py", line 270, in __call__
2023-02-18 02:08:43     await super().__call__(scope, receive, send)
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/starlette/applications.py", line 124, in __call__
2023-02-18 02:08:43     await self.middleware_stack(scope, receive, send)
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 184, in __call__
2023-02-18 02:08:43     raise exc
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/errors.py", line 162, in __call__
2023-02-18 02:08:43     await self.app(scope, receive, _send)
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/cors.py", line 92, in __call__
2023-02-18 02:08:43     await self.simple_response(scope, receive, send, request_headers=headers)
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/cors.py", line 147, in simple_response
2023-02-18 02:08:43     await self.app(scope, receive, send)
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/base.py", line 106, in __call__
2023-02-18 02:08:43     response = await self.dispatch_func(request, call_next)
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/fastapi_async_sqlalchemy/middleware.py", line 45, in dispatch
2023-02-18 02:08:43     return await call_next(request)
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/base.py", line 80, in call_next
2023-02-18 02:08:43     raise app_exc
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/base.py", line 69, in coro
2023-02-18 02:08:43     await self.app(scope, receive_or_disconnect, send_no_error)
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
2023-02-18 02:08:43     raise exc
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
2023-02-18 02:08:43     await self.app(scope, receive, sender)
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
2023-02-18 02:08:43     raise e
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
2023-02-18 02:08:43     await self.app(scope, receive, send)
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 706, in __call__
2023-02-18 02:08:43     await route.handle(scope, receive, send)
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 276, in handle
2023-02-18 02:08:43     await self.app(scope, receive, send)
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/starlette/routing.py", line 66, in app
2023-02-18 02:08:43     response = await func(request)
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/fastapi/routing.py", line 237, in app
2023-02-18 02:08:43     raw_response = await run_endpoint_function(
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/fastapi/routing.py", line 163, in run_endpoint_function
2023-02-18 02:08:43     return await dependant.call(**values)
2023-02-18 02:08:43   File "/code/./app/api/v1/endpoints/project.py", line 83, in create_project
2023-02-18 02:08:43     created = await crud.project.create(obj_in=project, created_by_id=None)
2023-02-18 02:08:43   File "/code/./app/crud/base_crud.py", line 161, in create
2023-02-18 02:08:43     db_obj = self.model.from_orm(obj_in.dict())  # type: ignore
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/sqlmodel/main.py", line 551, in from_orm
2023-02-18 02:08:43     m = cls()
2023-02-18 02:08:43   File "<string>", line 4, in __init__
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/state.py", line 481, in _initialize_instance
2023-02-18 02:08:43     with util.safe_reraise():
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/sqlalchemy/util/langhelpers.py", line 70, in __exit__
2023-02-18 02:08:43     compat.raise_(
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/sqlalchemy/util/compat.py", line 208, in raise_
2023-02-18 02:08:43     raise exception
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/sqlalchemy/orm/state.py", line 479, in _initialize_instance
2023-02-18 02:08:43     return manager.original_init(*mixed[1:], **kwargs)
2023-02-18 02:08:43   File "/usr/local/lib/python3.10/site-packages/sqlmodel/main.py", line 498, in __init__
2023-02-18 02:08:43     values, fields_set, validation_error = validate_model(
2023-02-18 02:08:43   File "pydantic/main.py", line 1077, in pydantic.main.validate_model
2023-02-18 02:08:43   File "pydantic/fields.py", line 877, in pydantic.fields.ModelField.validate
2023-02-18 02:08:43   File "pydantic/fields.py", line 1148, in pydantic.fields.ModelField._apply_validators
2023-02-18 02:08:43   File "pydantic/class_validators.py", line 287, in pydantic.class_validators._generic_validator_cls.lambda5
2023-02-18 02:08:43   File "/code/./app/models/project_model.py", line 30, in slugify_name
2023-02-18 02:08:43     repr_name = slugify(values['name'], separator="_")
2023-02-18 02:08:43 KeyError: 'name'

Somehow, the from_orm method does not have the field name.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions