sqlmodel icon indicating copy to clipboard operation
sqlmodel copied to clipboard

Loading an object from the database (vs init) produces different field types - it shouldn't

Open tasn opened this issue 4 years ago • 3 comments

First Check

  • [X] I added a very descriptive title to this issue.
  • [X] I used the GitHub search to find a similar issue and didn't find it.
  • [X] I searched the SQLModel documentation, with the integrated search.
  • [X] I already searched in Google "How to X in SQLModel" and didn't find any information.
  • [X] I already read and followed all the tutorial in the docs and didn't find an answer.
  • [X] I already checked if it is not related to SQLModel but to Pydantic.
  • [X] I already checked if it is not related to SQLModel but to SQLAlchemy.

Commit to Help

  • [X] I commit to help with one of those options 👆

Example Code

import sqlmodel as sqlm

class BarType(str):
    @property
    def with_prefix(self):
        return f"PREFIX! {self}"

class Foo(SQLModel, table=True):
    id: str = sqlm.Field(primary_key=True)

    bar: BarType

# Works

foo = Foo(id="some-id", bar="test")
assert isinstance(foo.bar, BarType)

# Though this fails:

foo = load_foo_from_db()
assert isinstance(foo.bar, BarType) # FAILS!

Description

The types are currently lying when loading from db. :)

Wanted Solution

They should work.

Wanted Code

Some thing as above, but works.

Alternatives

No response

Operating System

Linux

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.9

Additional Context

No response

tasn avatar Sep 23 '21 11:09 tasn

What is the type of foo.bar when you load it from the database?

jack-michaud avatar Oct 07 '21 21:10 jack-michaud

str

You can check out https://github.com/tiangolo/sqlmodel/blob/main/sqlmodel/main.py#L372 to see exactly what's going on.

To workaround this issue, I have a fork (which is what we use) that lets you customize the type in a few ways, this is one of them: https://github.com/tasn/sqlmodel/blob/fixes/sqlmodel/main.py#L378

Essentially what I do is create a custom string loader sqlalchemy type that instantiates the value after loading from the db (have the same for other base types), and I just force its usage here.

tasn avatar Oct 07 '21 22:10 tasn

This is still an issue on data returned from the database, seemingly for fields that use anything other than builtins.

jp-u avatar Mar 10 '24 09:03 jp-u