How to use nullable field with non-null default #2003
-
First Check
Example Codefrom sqlmodel import SQLModel, Field, Session, create_engine
class DefaultModel(SQLModel, table=True):
id: int = Field(primary_key=True)
field: int | None = Field(default=1, nullable=True)
engine = create_engine("sqlite:///:memory:")
SQLModel.metadata.create_all(engine)
with Session(engine) as session:
model = DefaultModel(field=None)
print(model.field) # None (as expected)
session.add(model)
session.commit()
session.refresh(model)
print(model.field) # 1 (inserts the default value instead of None)
model.field = None
session.commit()
session.refresh(model)
print(model.field) # None (workaround: this time null is set in the db)Description
Additionally, setting the field to Is applying the default to any Operating SystemWindows Operating System DetailsNo response Project Version2.13.4 Python Version3.13 Additional ContextI have not tested this with other DBs outside of sqlite. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
|
That default 1 isn't coming from Pydantic, it's a SQLAlchemy column default. To make unset give 1 but explicit None give NULL, move the default off the column so only the Pydantic side remains: from sqlalchemy import Column, Integer
field: int | None = Field(default=1, sa_column=Column(Integer, nullable=True))Keep |
Beta Was this translation helpful? Give feedback.
That default 1 isn't coming from Pydantic, it's a SQLAlchemy column default.
Field(default=1)attaches aScalarElementColumnDefault(1)to the column, and a scalar column default gets applied on INSERT whenever the value is None, so your explicit None gets replaced with 1. There's no column default on UPDATE (that'sonupdate), which is why setting it to None and committing again keeps the null.To make unset give 1 but explicit None give NULL, move the default off the column so only the Pydantic side remains:
Keep
default=1on the Field, that's now what fills 1 when the att…