-
-
Notifications
You must be signed in to change notification settings - Fork 435
Description
Hi! I believe I’ve found a small issue in the pydantic_model_creator
helper function.
Describe the bug
Source:
tortoise-orm/tortoise/contrib/pydantic/creator.py
Lines 527 to 530 in 4b4e4a5
if not field.pk and ( | |
field_name in self._optional or field.default is not None or field.null | |
): | |
ptype = Optional[ptype] |
In line 528, when generating field annotations, the logic currently considers a field optional if its default is anything other than None
(field.default is not None
). However, this can be misleading—for example, an integer field might have a default value of 0
, but None
is still not a valid input.
In such cases, the generated Pydantic model uses Optional[int]
, so the schema accepts None
, but that later causes an ValueError
at the ORM level bypassing schema validation at the HTTP level.
Let me know if this makes sense, or if there's another reason for this behavior I might have missed.
Stack versions:
- pydantic:
2.10.4
- tortoise-orm:
0.21.3
(also reproduced in the latest version)
To Reproduce
class Altitude(models.Model):
altitude = fields.FloatField(default=0, null=False)
AltitudeSchema = pydantic_model_creator(
Altitude,
name="AltitudeSchema",
)
# Generated field annotation
$ AltitudeSchema.__fields__["altitude"]
> FieldInfo(annotation=Union[float, NoneType], required=False, default=0, title='Altitude', json_schema_extra={})
Later, when using this schema with a None
value, it will be accepted by the schema but will fail when inserting into the database:
payload = AltitudeSchema(id=1, altitude=None)
await Altitude.create(**payload.model_dump())
Traceback (most recent call last):
...
File "<string>", line 2, in <module>
File "packages/tortoise/models.py", line 697, in _set_kwargs
raise ValueError(f"{key} is non nullable field, but null was passed")
ValueError: altitude is non nullable field, but null was passed
Expected behavior
I expected the Pydantic schema generated by the pydantic_model_creator
helper function to type as Optional
only the fields explicitly passed to the optional
parameter or those declared at the ORM level with null=True
.
Additional context
If I'm not missing anything, I think this issue could be fixed by changing the current if
block to:
if not field.pk and (
field_name in self._optional or field.default is None or field.null
):
Or even simpler:
if not field.pk and (
field_name in self._optional or field.null
)
The generated schema:
AltitudeSchema.__fields__["altitude"]
# FieldInfo(annotation=float, required=False, default=0, title='Altitude', json_schema_extra={})
AltitudeSchema(id=1, altitude=None)
# Traceback (most recent call last):
# File "<string>", line 1, in <module>
# /pydantic/main.py", line 214, in __init__
# validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# pydantic_core._pydantic_core.ValidationError: 1 validation error for AltitudeSchema
# altitude
# Input should be a valid number [type=float_type, input_value=None, input_type=NoneType]
# For further information visit https://errors.pydantic.dev/2.10/v/float_type