Skip to content

Instantly share code, notes, and snippets.

@Graeme22
Created May 5, 2026 18:29
Show Gist options
  • Select an option

  • Save Graeme22/71d518c5ea2815659b92e62e2e2448f8 to your computer and use it in GitHub Desktop.

Select an option

Save Graeme22/71d518c5ea2815659b92e62e2e2448f8 to your computer and use it in GitHub Desktop.
SQLModel class that actually validates
from typing import Any
from pydantic_core import PydanticUndefined as Undefined
from sqlmodel import Field
from sqlmodel import SQLModel as _SQLModel
from sqlmodel._compat import finish_init, is_table_model_class
class SQLModel(_SQLModel):
def __init__(__pydantic_self__, **data: Any) -> None:
# Uses something other than `self` the first arg to allow "self" as a
# settable attribute
# SQLAlchemy does very dark black magic and modifies the __init__ method in
# sqlalchemy.orm.instrumentation._generate_init()
# so, to make SQLAlchemy work, it's needed to explicitly call __init__ to
# trigger all the SQLAlchemy logic, it doesn't work using cls.__new__, setting
# attributes obj.__dict__, etc. The __init__ method has to be called. But
# there are cases where calling all the default logic is not ideal, e.g.
# when calling Model.model_validate(), as the validation is done outside
# of instance creation.
# At the same time, __init__ is what users would normally call, by creating
# a new instance, which should have validation and all the default logic.
# So, to be able to set up the internal SQLAlchemy logic alone without
# executing the rest, and support things like Model.model_validate(), we
# use a contextvar to know if we should execute everything.
if finish_init.get():
old_dict = __pydantic_self__.__dict__.copy()
__pydantic_self__.__pydantic_validator__.validate_python(
data,
self_instance=__pydantic_self__,
)
if not is_table_model_class(__pydantic_self__.__class__):
object.__setattr__(
__pydantic_self__,
"__dict__",
{**old_dict, **__pydantic_self__.__dict__},
)
else:
fields_set = __pydantic_self__.__pydantic_fields_set__.copy()
for key, value in {**old_dict, **__pydantic_self__.__dict__}.items():
setattr(__pydantic_self__, key, value)
object.__setattr__(
__pydantic_self__, "__pydantic_fields_set__", fields_set
)
for key in __pydantic_self__.__sqlmodel_relationships__:
value = data.get(key, Undefined)
if value is not Undefined:
setattr(__pydantic_self__, key, value)
@Graeme22
Copy link
Copy Markdown
Author

Graeme22 commented May 5, 2026

Usage:

class Hero(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    age: int

hero = Hero(age=4)
print(hero)
hero2 = Hero(age="oops!")
print(hero2)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment