I used the GitHub search to find a similar issue and didn't find it.
I searched the SQLModel documentation, with the integrated search.
I already searched in Google "How to X in SQLModel" and didn't find any information.
I already read and followed all the tutorial in the docs and didn't find an answer.
I already checked if it is not related to SQLModel but to Pydantic.
I already checked if it is not related to SQLModel but to SQLAlchemy.
Commit to Help
I commit to help with one of those options 👆
Example Code
frompydanticimportBaseModelfromsqlmodelimportSQLModel, FieldclassBaseModelTest(BaseModel):
id: intsome_bool: booldesc: strclassSQLModelTest(SQLModel, table=True):
id: int=Field(default=None, primary_key=True)
some_bool: booldesc: str# This will work as expectedsqlmodel_instance=SQLModelTest(id=3, some_bool=False, desc="This will work")
print(sqlmodel_instance)
# This will work as expectedpydantic_instance=BaseModelTest(id=3, some_bool=False, desc="This will work")
print(pydantic_instance)
# This will work but should notsqlmodel_instance=SQLModelTest(id=3, some_bool="blob", desc=False)
print(sqlmodel_instance)
# This will not work as expectedpydantic_instance=BaseModelTest(id=3, some_bool="blob", desc=False)
print(pydantic_instance)
Description
When creating a SQLModel class instance, I thought that I'd have all the advantages of pydantic and SQLAlchemy classes toghether.
I was quite surprised when I realized that SQLModel classes created with table=True do not validate data as a pydantic class would do (see my example code).
Having read about all SQLModel documentation, I didn't find anywhere this is stated.
Especially in https://sqlmodel.tiangolo.com/tutorial/fastapi/multiple-models/ it would make sense to explain that a table=True won't do data validation as a pydantic class would do.
Maybe I did not understand the purpose of SQLModel enough, but this is quite disturbing for me.
I think it would be really nice to update the documentation regarding this particular point.
Operating System
Windows
Operating System Details
No response
SQLModel Version
0.0.8
Python Version
Python 3.10.7 x64
Additional Context
PS: Sorry, I'm comming here from Tortoise-ORM, and it's my first time using SQLModel, so I cannot guarantee that I will be quite helpful resolving issues here yet ;) I'll do my best.
To guess, when used as a table object, there is no verification process because it is used to map data that has already been verified in database.
(I think because SQLModel use DeclarativeMeta when table=True. link)
In particular, when calling many objects from database, there is no unnecessary verification process, so there is a performance advantage.
(I haven't checked yet.)
Of course, if the verification process is essential, SQLModel.validate method can be used.
I've asked the same question before, but I'm just using SQLModel.validate method for now. I want to know why, too.
I do understand that too, reads from database don't need validation. But writes do. Nevertheless it's not really clear in the documentation.
And since SQLModel is supposed to reduce code duplication, having a class for ORM and a class for Pydantic validation.... doesn't help deduplicate.
Reacted by phi-friday, Christian Staudt, Tres DuBiel, alores96, Simone Ziraldo, ilkergzlkkr, Michael, Ars, Abdul Rauf, Görkem Tosun and 40 more
This feature/bug should be fully documented, as I (and many others) expect the SQL model to validate data. Only after doing a lot of digging to find out why one of my field_validator wasn't working did I come across this GitHub issue.
Reacted by Claudemir Firmino, Sam Laird, Alexey Kolyanov, Richard Ertel, Tan Jia Huei, Luciano, Yaar, espdev, Tomas, Nuno Cravino and 43 more
I agree - this just totally threw me off. I expected it to be fully validating my table data. why bother inheriting from BaseModel at all if not.
This feature/bug should be fully documented, as I (and many others) expect the SQL model to validate data. Only after doing a lot of digging to find out why one of my field_validator wasn't working did I come across this GitHub issue.
Reacted by shwu-jt, Mudassar Zahid, Michael, Adam Parkin, Janusz Dziurzyński, Johannes Hansen, Johnny Wezel, Aliaksei Urbanski, Brendan Maguire, Danila Mikhaltsov and 5 more
completely annoying bug. I've lost half a day trying to understand what was happening. I'll reconsider if SQLModel is actually the way to go. Thank you, guys!
Reacted by Michael, loudblow, Tom Barton-Owen, Aliaksei Urbanski, Danila Mikhaltsov, Tim O'Farrell, Stefan Schablowski, Ilya_Sagaidac and Frog Chen
That's not what I expected.
I have been looking for a solution in the docs (in SQLmodel and Pydantic too) for 3 days now.
Why would I expect an error from the DB rather than my backend application?
I mean, I don't consider myself a senior so I guess whoever is working on it knows better than me but:
If the intended behavior is waiting for the DB to raise an error. Why are my tests still committed?
The whole point for me of considering SQLModel was to avoid duplication required by the mapping from my data model (type checking with Pydantic) to the mapping of my database model (ORM). If this is not a bug, then SQLModel is totally useless.
Reacted by Alessio Birettoni, Michael, loudblow, Furkan Şenol, Karel Růžička, Louis Auneau, noorhonjol, Roman Pishchalnikov, Victor Mota, Brendan Maguire and 16 more
I see I'm late to this party after many hours spent banging my head against a wall in my code base. The fascinating part is that the model validators are called with model_validate but not model_validate_json. In case its useful at all for disambiguation, here's what I had written up to post as the replication for a new issue before finding this one:
You don't need multi-models. Here's a complete solution to address the problems:
from contextlib import contextmanager
from contextvars import ContextVar
from typing import Self
import sqlmodel as sm
_ONGOING_MODEL_VALIDATE: ContextVar[bool] = ContextVar('_ONGOING_MODEL_VALIDATE', False)
@contextmanager
def set_ongoing_model_validate():
token = _ONGOING_MODEL_VALIDATE.set(True)
yield
_ONGOING_MODEL_VALIDATE.reset(token)
class OurBase(sm.SQLModel):
model_config = {'validate_assignment': True}
def __init__(self, **data):
if self.model_config.get('table', False) and not _ONGOING_MODEL_VALIDATE.get():
self_copy = self.model_copy()
self.__pydantic_validator__.validate_python(data, self_instance=self_copy)
data = self_copy.model_dump()
self.__dict__ |= self_copy.__dict__
super().__init__(**data)
@classmethod
def model_validate(cls: type[Self], *args, **kwargs) -> Self:
with set_ongoing_model_validate():
return super().model_validate(*args, **kwargs)
Derive from this base (modify model_config etc if needed) and you should be fine. Given the age, I'm not hopeful for any official solution landing, so I'm just using this and moving on. To know why/how it works, read on.
You don't need multi-models. Here's a complete solution to address the problems:
[...]
Derive from this base (modify model_config etc if needed) and you should be fine. Given the age, I'm not hopeful for any official solution landing, so I'm just using this and moving on. To know why/how it works, read on.
To me, the whole point of using a library is to avoid digging in its protected attributes and private methods. Running undocumented code in an untested way based on a comment in a Github thread dosen't feel appealing.
This is the first paragraph of the README :
It combines SQLAlchemy and Pydantic and tries to simplify the code you write as much as possible, allowing you to reduce the code duplication to a minimum, but while getting the best developer experience possible.
I surely don't understand all the pros and cons of this library as it is used by a lot of people, but my usecase, which I thought simple, isn't covered. Seeing the hundreds of reactions and the number of issues opened on this subject, I would say something isn't working as people expected. Maybe it should be made clear from the start that this usecase is not covered, and that people will need to write separate classes extending eachother to manage the validation and the orm separately. The README says it "combines" pydantics and SQLAlchemy but it is unclear to me how it combines them.
In any case, thank you for your work, provided for free to me and others. I hope I'll find another usecase for it.
Reacted by Julien-Delavisse, Roman Bange, Keith Byrne, Michael, Michel Klueger, Kevin A. Mitchell, Ali Baharev, Adam Best, Ilya_Sagaidac, Sasha Patotski and 6 more
The library claims (statement) to combine pydantic and sqlalchemy models, but in its very basic use-case it doesn't validate the request against the model when used with FastAPI which defeats the purpose.
Even the code from the simple api tutorial returns a 500 internal error instead of a 422 validation error. This is the very first endpoint users create with the library, so either the library description should be updated with corrected claims, or it should be made clear from get-go that defining a class with table=True is not validated due to these (listed) reasons.
# great simple way of processing the Hero class@app.post("/heroes/")defcreate_hero(hero: Hero):
withSession(engine) assession:
session.add(hero)
session.commit()
session.refresh(hero)
returnhero
Please don't get me wrong, the library is great in the fact that I don't need to deal with sqlalchemy types and simply create a pydantic model and interact with the database. But I still need a separate model to first validate the user input. The final list of models becomes something like below, see my comments please.
# common fieldsclassHeroBase(SQLModel):
name: str=Field(index=True)
secret_name: strage: int|None=Field(default=None, index=True)
# database modelclassHero(HeroBase, table=True):
id: int|None=Field(default=None, primary_key=True)
# model for post requestsclassHeroCreate(HeroBase):
pass# model for responses# practically the same as Hero but reasons ...classHeroPublic(HeroBase):
id: int
Reacted by Danila Mikhaltsov and Aliaksei Urbanski
Activity
phi-friday commented on Sep 29, 2022
To guess, when used as a table object, there is no verification process because it is used to map data that has already been verified in database.
(I think because SQLModel use DeclarativeMeta when table=True. link)
In particular, when calling many objects from database, there is no unnecessary verification process, so there is a performance advantage.
(I haven't checked yet.)
Of course, if the verification process is essential, SQLModel.validate method can be used.
I've asked the same question before, but I'm just using SQLModel.validate method for now. I want to know why, too.
deajan commented on Sep 29, 2022
I do understand that too, reads from database don't need validation. But writes do. Nevertheless it's not really clear in the documentation.
And since SQLModel is supposed to reduce code duplication, having a class for ORM and a class for Pydantic validation.... doesn't help deduplicate.
phi-friday commented on Oct 1, 2022
@deajan
I don't know the answer to why, but I found a simple way to solve it.
link
5p4k commented on Dec 8, 2023
I think this is answered here: #52 (comment)
For future reference, I found this while looking for why model_validate_json did not properly validate for a SQLModel with table=True.
realchandan commented on Jul 13, 2024
This feature/bug should be fully documented, as I (and many others) expect the SQL model to validate data. Only after doing a lot of digging to find out why one of my field_validator wasn't working did I come across this GitHub issue.
mg3146 commented on Oct 28, 2024
I agree - this just totally threw me off. I expected it to be fully validating my table data. why bother inheriting from BaseModel at all if not.
RamiroFartoBello commented on Nov 20, 2024
completely annoying bug. I've lost half a day trying to understand what was happening. I'll reconsider if SQLModel is actually the way to go. Thank you, guys!
iloveitaly commented on Nov 26, 2024
This was also very surprising to me. Looks like this PR may fix the issue, although it's unclear if it's the right approach.
fastkits commented on Feb 14, 2025
when update new version ?
ml31415 commented on Mar 2, 2025
I don't think, that there will be a version fixing this. It rather looks like, that this oddity is considered a feature. Sadly.
SDVoGo commented on Mar 15, 2025
That's not what I expected.
I have been looking for a solution in the docs (in SQLmodel and Pydantic too) for 3 days now.
Why would I expect an error from the DB rather than my backend application?
I mean, I don't consider myself a senior so I guess whoever is working on it knows better than me but:
If the intended behavior is waiting for the DB to raise an error. Why are my tests still committed?
My problem was really stupid.
name and formula are strings not None. I accidentally found that empty string was ok for both but I didn't like that.
I can't use @model_validator(mode="after") because won't consider any validator.
rainergo commented on Mar 16, 2025
The whole point for me of considering SQLModel was to avoid duplication required by the mapping from my data model (type checking with Pydantic) to the mapping of my database model (ORM). If this is not a bug, then SQLModel is totally useless.
Samreay commented on Aug 14, 2025
I see I'm late to this party after many hours spent banging my head against a wall in my code base. The fascinating part is that the model validators are called with model_validate but not model_validate_json. In case its useful at all for disambiguation, here's what I had written up to post as the replication for a new issue before finding this one:
Outputs:
m-danya commented on Aug 14, 2025
Well, it was really unpleasant to discover... The whole point of the library, to combine pydantic and sqlalchemy, seems to have failed.
This example prints <class 'str'>:
spandan-sharma commented on Sep 2, 2025
Pasting the TL;DR from here
TL;DR
You don't need multi-models. Here's a complete solution to address the problems:
from contextlib import contextmanager from contextvars import ContextVar from typing import Self import sqlmodel as sm _ONGOING_MODEL_VALIDATE: ContextVar[bool] = ContextVar('_ONGOING_MODEL_VALIDATE', False) @contextmanager def set_ongoing_model_validate(): token = _ONGOING_MODEL_VALIDATE.set(True) yield _ONGOING_MODEL_VALIDATE.reset(token) class OurBase(sm.SQLModel): model_config = {'validate_assignment': True} def __init__(self, **data): if self.model_config.get('table', False) and not _ONGOING_MODEL_VALIDATE.get(): self_copy = self.model_copy() self.__pydantic_validator__.validate_python(data, self_instance=self_copy) data = self_copy.model_dump() self.__dict__ |= self_copy.__dict__ super().__init__(**data) @classmethod def model_validate(cls: type[Self], *args, **kwargs) -> Self: with set_ongoing_model_validate(): return super().model_validate(*args, **kwargs)Derive from this base (modify model_config etc if needed) and you should be fine. Given the age, I'm not hopeful for any official solution landing, so I'm just using this and moving on. To know why/how it works, read on.
leogout commented on Nov 27, 2025
To me, the whole point of using a library is to avoid digging in its protected attributes and private methods. Running undocumented code in an untested way based on a comment in a Github thread dosen't feel appealing.
This is the first paragraph of the README :
I surely don't understand all the pros and cons of this library as it is used by a lot of people, but my usecase, which I thought simple, isn't covered. Seeing the hundreds of reactions and the number of issues opened on this subject, I would say something isn't working as people expected. Maybe it should be made clear from the start that this usecase is not covered, and that people will need to write separate classes extending eachother to manage the validation and the orm separately. The README says it "combines" pydantics and SQLAlchemy but it is unclear to me how it combines them.
In any case, thank you for your work, provided for free to me and others. I hope I'll find another usecase for it.
MarleTangible commented on Jan 6, 2026
I just would like to make this absolutely clear.
The library claims (statement) to combine pydantic and sqlalchemy models, but in its very basic use-case it doesn't validate the request against the model when used with FastAPI which defeats the purpose.
Even the code from the simple api tutorial returns a 500 internal error instead of a 422 validation error. This is the very first endpoint users create with the library, so either the library description should be updated with corrected claims, or it should be made clear from get-go that defining a class with table=True is not validated due to these (listed) reasons.
Please don't get me wrong, the library is great in the fact that I don't need to deal with sqlalchemy types and simply create a pydantic model and interact with the database. But I still need a separate model to first validate the user input. The final list of models becomes something like below, see my comments please.
shubhamyx commented on Apr 21, 2026
"Hi, I've opened a PR to address the documentation gap mentioned here: #1880"
Jamim commented on May 6, 2026
Hey @shubhamyx,
Quote marks in your message tell us you are an AI agent 💯
Why don't you disclose that in your profile?