Fields with db_default fail on full_clean()

Trying to implement Django 5’s new db_default attribute for fields (using Django 5.0.2)

Using the following fields as examples:

    editable = models.BooleanField(db_default=True)
    leadtime = models.PositiveSmallIntegerField(
        db_default=0, verbose_name="Lead time (days)", blank=True
    )

If editable or leadtime not specified when creating a new instance of a model containing them, would expect that ORM would not throw error, would save instance, and that the value of editable would be set as True and leadtime as 0 at the database level.

Thus when executing the following to create a new Product instance, with both editable and leadtime as fields:

    product_obj = models.Product(
        id=id,
        name=name,
        inventory_type=inventory_type,
    )
    product_obj.full_clean()
    product_obj.save()

would expect to succeed.

Instead full_clean() raises a ValidationError :

django.core.exceptions.ValidationError: 
{'editable': ['β€œ<django.db.models.expressions.DatabaseDefault object 
at 0x151db1c70>” value must be either True or False.'], 
'leadtime': ['β€œ<django.db.models.expressions.DatabaseDefault object 
at 0x14e22bad0>” value must be an integer.'}

and similar behavior occurs throughout my codebase for any field for which db_default is set .

Clearly I’m misunderstanding how db_default should be used. (Develop with Django daily for 6 years, so this is frustrating.) Does anyone have feedback on what I’m doing wrong?

That is correct. That is exactly what happens.

And, when you call save on the instance, the instance is updated with the db_default values applied.

Note that calling save on an instance does not call any of the clean methods, so the error does not get thrown if you create the instance and save it.

<opinion>
I think you could handle this a couple of different ways.

You could add the fields having db_default attributes to the exclude parameter of full_clean call or create a custom clean method for that field to check the value (if provided) or to allow for a null value.
</opinion>

1 Like

As mentioned on Discord I think this is the db_default flavoured version of #35127 (Model.full_clean() errors with GeneratedField) – Django and I would encourage you to file a ticket for it.

1 Like

Have submitted a ticket for consideration, suggesting either excluding db_default fields from full_clean() or to incorporate the workarounds @KenWhitesell suggested into the documentation –– I don’t think I’m the only person who will expect that the db_default will work the way I did

Thank you @charettes for your discussion in the ticket, you expressed the issue better than I did.

For anyone reading who would like to follow progress: the ticket was accepted, look forward to the change whenever it rolls out: https://code.djangoproject.com/ticket/35223