Skip to content

Commit a338223

Browse files
committed
🐛 Forward by_alias and by_name to model_validate
SQLModel overrides model_validate but did not pass through the by_alias and by_name arguments that Pydantic supports. Since SQLModel requires pydantic>=2.11, where both are always available, calling Model.model_validate(data, by_alias=True) (or by_name=True) raised TypeError: unexpected keyword argument. Add both parameters to the model_validate override and to sqlmodel_validate, forwarding them to validate_python.
1 parent 075fecb commit a338223

3 files changed

Lines changed: 31 additions & 0 deletions

File tree

sqlmodel/_compat.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,8 @@ def sqlmodel_validate(
280280
strict: bool | None = None,
281281
from_attributes: bool | None = None,
282282
context: dict[str, Any] | None = None,
283+
by_alias: bool | None = None,
284+
by_name: bool | None = None,
283285
update: dict[str, Any] | None = None,
284286
) -> _TSQLModel:
285287
if not is_table_model_class(cls):
@@ -303,6 +305,8 @@ def sqlmodel_validate(
303305
strict=strict,
304306
from_attributes=from_attributes,
305307
context=context,
308+
by_alias=by_alias,
309+
by_name=by_name,
306310
self_instance=new_obj,
307311
)
308312
# Capture fields set to restore it later

sqlmodel/main.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,8 @@ def model_validate( # ty: ignore[invalid-method-override]
876876
strict: bool | None = None,
877877
from_attributes: bool | None = None,
878878
context: builtins.dict[str, Any] | None = None,
879+
by_alias: bool | None = None,
880+
by_name: bool | None = None,
879881
update: builtins.dict[str, Any] | None = None,
880882
) -> _TSQLModel:
881883
return sqlmodel_validate(
@@ -884,6 +886,8 @@ def model_validate( # ty: ignore[invalid-method-override]
884886
strict=strict,
885887
from_attributes=from_attributes,
886888
context=context,
889+
by_alias=by_alias,
890+
by_name=by_name,
887891
update=update,
888892
)
889893

tests/test_aliases.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,26 @@ class M(SQLModel):
179179
assert m.f == "ok"
180180
data = m.model_dump(by_alias=True)
181181
assert "custom" in data and "gen_f" not in data
182+
183+
184+
@pytest.mark.parametrize("model", [PydanticUser, SQLModelUser])
185+
def test_model_validate_by_name(
186+
model: type[PydanticUser] | type[SQLModelUser],
187+
):
188+
# By default, a field with an alias can't be populated by its name
189+
with pytest.raises(ValidationError):
190+
model.model_validate({"full_name": "Greg"})
191+
# With by_name=True, the field name is accepted
192+
user = model.model_validate({"full_name": "Greg"}, by_name=True)
193+
assert user.full_name == "Greg"
194+
195+
196+
@pytest.mark.parametrize("model", [PydanticUser, SQLModelUser])
197+
def test_model_validate_by_alias_and_by_name(
198+
model: type[PydanticUser] | type[SQLModelUser],
199+
):
200+
# With both enabled, either the alias or the field name is accepted
201+
by_alias = model.model_validate({"fullName": "Helen"}, by_alias=True, by_name=True)
202+
assert by_alias.full_name == "Helen"
203+
by_name = model.model_validate({"full_name": "Helen"}, by_alias=True, by_name=True)
204+
assert by_name.full_name == "Helen"

0 commit comments

Comments
 (0)