diff --git a/sqlmodel/__init__.py b/sqlmodel/__init__.py index f71b5265b1..3945c38f3f 100644 --- a/sqlmodel/__init__.py +++ b/sqlmodel/__init__.py @@ -1,5 +1,9 @@ __version__ = "0.0.35" +# Re-export from Pydantic +from pydantic import AliasChoices as AliasChoices +from pydantic import AliasPath as AliasPath + # Re-export from SQLAlchemy from sqlalchemy.engine import create_engine as create_engine from sqlalchemy.engine import create_mock_engine as create_mock_engine diff --git a/sqlmodel/main.py b/sqlmodel/main.py index 300031de8b..4afd8d0dba 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -23,7 +23,7 @@ overload, ) -from pydantic import BaseModel, EmailStr +from pydantic import AliasChoices, AliasPath, BaseModel, EmailStr from pydantic.fields import FieldInfo as PydanticFieldInfo from sqlalchemy import ( Boolean, @@ -240,7 +240,7 @@ def Field( *, default_factory: NoArgAnyCallable | None = None, alias: str | None = None, - validation_alias: str | None = None, + validation_alias: str | AliasPath | AliasChoices | None = None, serialization_alias: str | None = None, title: str | None = None, description: str | None = None, @@ -283,7 +283,7 @@ def Field( *, default_factory: NoArgAnyCallable | None = None, alias: str | None = None, - validation_alias: str | None = None, + validation_alias: str | AliasPath | AliasChoices | None = None, serialization_alias: str | None = None, title: str | None = None, description: str | None = None, @@ -335,7 +335,7 @@ def Field( *, default_factory: NoArgAnyCallable | None = None, alias: str | None = None, - validation_alias: str | None = None, + validation_alias: str | AliasPath | AliasChoices | None = None, serialization_alias: str | None = None, title: str | None = None, description: str | None = None, @@ -368,7 +368,7 @@ def Field( *, default_factory: NoArgAnyCallable | None = None, alias: str | None = None, - validation_alias: str | None = None, + validation_alias: str | AliasPath | AliasChoices | None = None, serialization_alias: str | None = None, title: str | None = None, description: str | None = None, diff --git a/tests/test_aliases.py b/tests/test_aliases.py index f0ebf747b4..291832407a 100644 --- a/tests/test_aliases.py +++ b/tests/test_aliases.py @@ -1,7 +1,9 @@ import pytest +from pydantic import AliasChoices as PAliasChoices +from pydantic import AliasPath as PAliasPath from pydantic import BaseModel, ValidationError from pydantic import Field as PField -from sqlmodel import Field, SQLModel +from sqlmodel import AliasChoices, AliasPath, Field, SQLModel """ Alias tests for SQLModel and Pydantic compatibility @@ -95,10 +97,18 @@ def test_json_by_alias( class PydanticUserV2(BaseModel): first_name: str = PField(validation_alias="firstName", serialization_alias="f_name") + second_name: str | None = PField( + default=None, validation_alias=PAliasChoices("secondName", "surname") + ) + nickname: str | None = PField(default=None, validation_alias=PAliasPath("names", 2)) class SQLModelUserV2(SQLModel): first_name: str = Field(validation_alias="firstName", serialization_alias="f_name") + second_name: str | None = Field( + default=None, validation_alias=AliasChoices("secondName", "surname") + ) + nickname: str | None = Field(default=None, validation_alias=AliasPath("names", 2)) @pytest.mark.parametrize("model", [PydanticUserV2, SQLModelUserV2]) @@ -109,6 +119,27 @@ def test_create_with_validation_alias( assert user.first_name == "John" +@pytest.mark.parametrize("model", [PydanticUserV2, SQLModelUserV2]) +def test_create_with_validation_alias_alias_choices( + model: type[PydanticUserV2] | type[SQLModelUserV2], +): + user = model.model_validate({"firstName": "John", "secondName": "Doe"}) + assert user.second_name == "Doe" + + user2 = model.model_validate({"firstName": "John", "surname": "Doe"}) + assert user2.second_name == "Doe" + + +@pytest.mark.parametrize("model", [PydanticUserV2, SQLModelUserV2]) +def test_create_with_validation_alias_alias_path( + model: type[PydanticUserV2] | type[SQLModelUserV2], +): + user = model.model_validate( + {"firstName": "John", "names": ["John", "Doe", "Johnny"]} + ) + assert user.nickname == "Johnny" + + @pytest.mark.parametrize("model", [PydanticUserV2, SQLModelUserV2]) def test_serialize_with_serialization_alias( model: type[PydanticUserV2] | type[SQLModelUserV2],