Field Mapping and Alias Resolution
Field mapping and alias resolution allow you to decouple the internal names of your fields from the keys used in external data formats like JSON. This is controlled through field-level alias definitions and global configuration settings in CoreConfig.
Mapping Input Data with Validation Aliases
To map an external key to an internal field name during validation, use the validation_alias property. This is available on ModelField, TypedDictField, and DataclassField.
from pydantic_core import SchemaValidator, core_schema
v = SchemaValidator(
core_schema.typed_dict_schema(
fields={
'internal_name': core_schema.typed_dict_field(
schema=core_schema.int_schema(),
validation_alias='external_key'
)
}
)
)
# Validates using the alias
assert v.validate_python({'external_key': 123}) == {'internal_name': 123}
Enabling Validation by Name
By default, if a validation_alias is provided, the validator only looks for that alias. You can enable fallback to the field's internal name by setting validate_by_name=True in the CoreConfig.
from pydantic_core import SchemaValidator, core_schema, CoreConfig
v = SchemaValidator(
core_schema.typed_dict_schema(
fields={
'field_a': core_schema.typed_dict_field(
schema=core_schema.int_schema(),
validation_alias='FieldA'
)
},
config=CoreConfig(validate_by_name=True)
)
)
# Works with alias
assert v.validate_python({'FieldA': 1}) == {'field_a': 1}
# Works with name because validate_by_name=True
assert v.validate_python({'field_a': 1}) == {'field_a': 1}
Advanced Validation Paths
The validation_alias can be more than just a string. It supports complex paths and multiple alternative locations.
Extracting Nested Data
You can provide a list of strings and integers to extract data from nested structures. The first item in the list must be a string (the key in the top-level dictionary).
v = SchemaValidator(
core_schema.typed_dict_schema(
fields={
'user_id': core_schema.typed_dict_field(
# Path: look in 'metadata', then 'user', then index 0
validation_alias=['metadata', 'user', 0],
schema=core_schema.int_schema()
)
}
)
)
assert v.validate_python({'metadata': {'user': [123, 'other']}}) == {'user_id': 123}
Multiple Alternative Paths
If you provide a list of lists, the validator will try each path in order until it finds a value.
v = SchemaValidator(
core_schema.typed_dict_schema(
fields={
'field_a': core_schema.typed_dict_field(
# Try 'primary_key' first, then fallback to 'legacy_key'
validation_alias=[['primary_key'], ['legacy_key']],
schema=core_schema.int_schema()
)
}
)
)
assert v.validate_python({'primary_key': 1}) == {'field_a': 1}
assert v.validate_python({'legacy_key': 2}) == {'field_a': 2}
Controlling Output with Serialization Aliases
Use serialization_alias to define the key used when converting the object back to a dictionary or JSON.
from pydantic_core import SchemaSerializer, core_schema
s = SchemaSerializer(
core_schema.typed_dict_schema(
{
'cat': core_schema.typed_dict_field(
core_schema.int_schema(),
serialization_alias='Meow'
),
}
)
)
value = {'cat': 0}
# By default, serialization uses internal names
assert s.to_python(value) == {'cat': 0}
# Use by_alias=True to use the serialization_alias
assert s.to_python(value, by_alias=True) == {'Meow': 0}
You can make serialization by alias the default behavior by setting serialize_by_alias=True in CoreConfig.
Error Reporting Locations
The loc_by_alias configuration option determines whether validation errors report the internal field name or the alias path.
from pydantic_core import SchemaValidator, core_schema, CoreConfig, ValidationError
import pytest
v = SchemaValidator(
core_schema.typed_dict_schema(
fields={
'field_a': core_schema.typed_dict_field(
validation_alias='FieldA',
schema=core_schema.int_schema()
)
},
config=CoreConfig(loc_by_alias=True) # Default behavior
)
)
try:
v.validate_python({'FieldA': 'not_an_int'})
except ValidationError as e:
# Error location uses the alias 'FieldA'
assert e.errors()[0]['loc'] == ('FieldA',)
v_no_alias_loc = SchemaValidator(
core_schema.typed_dict_schema(
fields={
'field_a': core_schema.typed_dict_field(
validation_alias='FieldA',
schema=core_schema.int_schema()
)
},
config=CoreConfig(loc_by_alias=False)
)
)
try:
v_no_alias_loc.validate_python({'FieldA': 'not_an_int'})
except ValidationError as e:
# Error location uses the internal name 'field_a'
assert e.errors()[0]['loc'] == ('field_a',)
Troubleshooting
- Required Fields and Defaults: A field cannot be marked as
required=Trueif it is wrapped in awith_default_schema. - Path Constraints: When using a list for
validation_alias, the first element must be a string. Subsequent elements can be strings (for dict keys) or integers (for list indices). - Config Conflicts: You cannot set both
validate_by_alias=Falseandvalidate_by_name=Falsesimultaneously, as this would leave the validator with no way to identify the field. - Serialization Precedence: The
by_aliasargument passed directly toto_pythonorto_jsonat runtime always takes precedence over theserialize_by_aliassetting inCoreConfig.