Describe the bug
I have used datamodel-code-generator
with a custom mapping to create a Pydantic v2 model. Doing that resulted in field names having the same name as other models which messes up validation for Optional fields.
I believe the bug (?) is, independent of specific settings, present for all cases where one might use optional fields and a mapping.
To Reproduce
The JSON Schema roughly looks like this
{
"title": "title1",
"type": "object",
"properties": {
"F00000001173": {
"title": "title2",
"type": "string",
"enum": ["001", "002", "003"]
},
"G00000001490": {
"title": "title3",
"type": "object",
"properties": {
"G00000001477": {
"title": "title4",
"type": "object",
"properties": {},
"required": ["F60000000227", "G60000000083", "G60000000093"]
},
"F00000002548": {
"title": "title5",
"type": "number",
"multipleOf": 0.01,
"minimum": 0
},
"F60000000296": {
"type": "array",
"items": {
"title": "title6",
"type": "string"
},
"minItems": 0
}
},
"required": ["G00000001477", "F00000002548", "F60000000296"]
}
},
"required": ["F00000001173"]
}
and a mapping between the ID fields and some more descriptive names was used (to make them more readable).
{
"F00000002548": "field1",
"G00000001490": "Model2",
"F00000001173": "field3",
"F60000000296": "field4"
}
This resulted in a code that looks like this
class Model2(BaseModel):
model_config = ConfigDict(
extra="allow",
populate_by_name=True,
)
field1: Annotated[float, Field(alias="F00000002548", ge=0.0, multiple_of=0.01)]
field2: Annotated[List[str], Field(alias="F60000000296", min_length=0)]
class Model1(BaseModel):
model_config = ConfigDict(
extra="allow",
populate_by_name=True,
)
field1: Annotated[Literal["001", "002", "003"], Field(alias="F00000001173")]
Model2: Annotated[Optional[Model2], Field(alias="G00000001490")] = None
where the problem is that the field should not be called Model2
like the class is.
Used commandline:
$ datamodel-codegen --input schema.json --target-python-version 3.10 --use-annotated --field-constraints --enum-field-as-literal all --allow-population-by-field-name --allow-population-by-field-name --output-model-type pydantic_v2.BaseModel --output schema.py
Expected behavior
The issue is fixed by making sure that the field names aren't the same as the other model names.
I achieved this temporarily by modifying the .jinja2
template like this
{%- for field in fields -%}
{%- if not field.annotated and field.field %}
{{ field.name | lower }}: {{ field.type_hint }} = {{ field.field }}
{%- else %}
{%- if field.annotated %}
{{ field.name | lower }}: {{ field.annotated }}
{%- else %}
{{ field.name | lower }}: {{ field.type_hint }}
{%- endif %}
{%- if not field.required or field.data_type.is_optional or field.nullable
%} = {{ field.represented_default }}
{%- endif -%}
{%- endif %}
{%- if field.docstring %}
"""
{{ field.docstring | indent(4) }}
"""
{%- endif %}
Version:
3.10
0.22.0
Additional context
Is there a way to modify this consistently? Passing the custom_template_dir
argument didn't seem to work for me.
If this is indeed a bug, I'm happy to provide a PR if someone can tell me where the field names are created! :)
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too