-
-
Notifications
You must be signed in to change notification settings - Fork 759
Description
Privileged issue
- I'm @tiangolo or he asked me directly to create an issue here.
Issue Content
Currently alias
parameter doesn't work as expected with Pydantic V2 installed.
Let's use this issue to track this.
👇 Here is a list of tests that showcase the problem (in the details):
from typing import Type, Union
import pytest
from pydantic import VERSION, BaseModel, ValidationError
from pydantic import Field as PField
from sqlmodel import Field, SQLModel
# -----------------------------------------------------------------------------------
# Models
class PydanticUser(BaseModel):
full_name: str = PField(alias="fullName")
class SQLModelUser(SQLModel):
full_name: str = Field(alias="fullName")
# Models with config (validate_by_name=True)
if VERSION.startswith("2."):
class PydanticUserWithConfig(PydanticUser):
model_config = {"validate_by_name": True}
class SQLModelUserWithConfig(SQLModelUser):
model_config = {"validate_by_name": True}
else:
class PydanticUserWithConfig(PydanticUser):
class Config:
allow_population_by_field_name = True
class SQLModelUserWithConfig(SQLModelUser):
class Config:
allow_population_by_field_name = True
# -----------------------------------------------------------------------------------
# Tests
# Test validate by name
@pytest.mark.parametrize("model", [PydanticUser, SQLModelUser])
def test_create_with_field_name(model: Union[Type[PydanticUser], Type[SQLModelUser]]):
with pytest.raises(ValidationError):
model(full_name="Alice")
@pytest.mark.parametrize("model", [PydanticUserWithConfig, SQLModelUserWithConfig])
def test_create_with_field_name_with_config(
model: Union[Type[PydanticUserWithConfig], Type[SQLModelUserWithConfig]],
):
user = model(full_name="Alice")
assert user.full_name == "Alice"
# Test validate by alias
@pytest.mark.parametrize(
"model",
[PydanticUser, SQLModelUser, PydanticUserWithConfig, SQLModelUserWithConfig],
)
def test_create_with_alias(
model: Union[
Type[PydanticUser],
Type[SQLModelUser],
Type[PydanticUserWithConfig],
Type[SQLModelUserWithConfig],
],
):
user = model(fullName="Bob") # using alias
assert user.full_name == "Bob"
# Test validate by name and alias
@pytest.mark.parametrize("model", [PydanticUserWithConfig, SQLModelUserWithConfig])
def test_create_with_both_prefers_alias(
model: Union[Type[PydanticUserWithConfig], Type[SQLModelUserWithConfig]],
):
user = model(full_name="IGNORED", fullName="Charlie")
assert user.full_name == "Charlie" # alias should take precedence
# Test serialize
@pytest.mark.parametrize("model", [PydanticUser, SQLModelUser])
def test_dict_default_uses_field_names(
model: Union[Type[PydanticUser], Type[SQLModelUser]],
):
user = model(fullName="Dana")
data = user.dict()
assert "full_name" in data
assert "fullName" not in data
assert data["full_name"] == "Dana"
# Test serialize by alias
@pytest.mark.parametrize("model", [PydanticUser, SQLModelUser])
def test_dict_default_uses_aliases(
model: Union[Type[PydanticUser], Type[SQLModelUser]],
):
user = model(fullName="Dana")
data = user.dict(by_alias=True)
assert "fullName" in data
assert "full_name" not in data
assert data["fullName"] == "Dana"
# Test json by alias
@pytest.mark.parametrize("model", [PydanticUser, SQLModelUser])
def test_json_by_alias(
model: Union[Type[PydanticUser], Type[SQLModelUser]],
):
user = model(fullName="Frank")
json_data = user.json(by_alias=True)
assert ('"fullName":"Frank"' in json_data) or ('"fullName": "Frank"' in json_data)
assert "full_name" not in json_data
When run with Pydantic V2:
t.py::test_create_with_field_name[PydanticUser] PASSED
t.py::test_create_with_field_name[SQLModelUser] FAILED
t.py::test_create_with_field_name_with_config[PydanticUserWithConfig] PASSED
t.py::test_create_with_field_name_with_config[SQLModelUserWithConfig] PASSED
t.py::test_create_with_alias[PydanticUser] PASSED
t.py::test_create_with_alias[SQLModelUser] FAILED
t.py::test_create_with_alias[PydanticUserWithConfig] PASSED
t.py::test_create_with_alias[SQLModelUserWithConfig] FAILED
t.py::test_create_with_both_prefers_alias[PydanticUserWithConfig] PASSED
t.py::test_create_with_both_prefers_alias[SQLModelUserWithConfig] FAILED
t.py::test_dict_default_uses_field_names[PydanticUser] PASSED
t.py::test_dict_default_uses_field_names[SQLModelUser] FAILED
t.py::test_dict_default_uses_aliases[PydanticUser] PASSED
t.py::test_dict_default_uses_aliases[SQLModelUser] FAILED
t.py::test_json_by_alias[PydanticUser] PASSED
t.py::test_json_by_alias[SQLModelUser] FAILED
All tests parameterized with both, Pydantic model and SQLModel model, to show the difference in behavior.
With Pydantic V1 all tests pass.
With Pydantic V2 most of tests fail with SQLModel model.
I would also expect that alias
is used as a default value of column name. But it should be possible to override it by providing sa_column=Column("column_name")
or sa_column_kwargs={"name": "column_name"}
.
Any feedback is welcome. Please, review the set of tests, suggest use-cases that are currently not covered.
Would be nice to add set of tests for validation_alias
and serialization_alias
as well.