Skip to content

Bug: pydantic_model_creator incorrectly marks fields as Optional when default is not None #1977

@fullonic

Description

@fullonic

Hi! I believe I’ve found a small issue in the pydantic_model_creator helper function.

Describe the bug
Source:

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions