Opened 5 months ago
Last modified 3 months ago
#35575 closed New feature
Model.full_clean() does not recalculate GeneratedFields prior to validating model constraints — at Version 3
Reported by: | Mark Gensler | Owned by: | Mark Gensler |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 5.0 |
Severity: | Normal | Keywords: | generatedfield uniqueconstraint checkconstraint |
Cc: | Mariusz Felisiak, Lily Foote, Simon Charette | Triage Stage: | Ready for checkin |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
GeneratedField
s on a model instance are not recalculated during Model.full_clean()
. Therefore, if a GeneratedField
is included in the *expressions
or fields
parameters of a UniqueConstraint
or CheckConstraint
in the instance's Model._meta
, the new values of the GeneratedField
attribute are not used by BaseConstraint.validate()
.
Instead, the model instance's GeneratedField
attribute will return the value which corresponds to the most recent refresh of the instance from the database. If the instance is new and has not yet been saved, the following error is raised:
AttributeError: Cannot read a generated field from an unsaved model.
An IntegrityError
is correctly raised when calling Model.save()
if any constraints involving GeneratedField
s are violated.
Instead, the recalculated values for GeneratedField
s should be used when checking constraints.
This ticket was raised after fixing the bug in #35560 with PR https://github.com/django/django/pull/18309.
Change History (3)
comment:1 by , 5 months ago
comment:2 by , 5 months ago
Description: | modified (diff) |
---|
comment:3 by , 5 months ago
Description: | modified (diff) |
---|
I'm happy to start working on this. I will raise a PR and add failing tests to catch the bug shortly.
Before writing any code to address this, I'd like to discuss where best to apply the fix. I see two possible options:
GeneratedField
attribute values on the fly as part of callingConstraint.validate()
. This will leave the instance attributes unchanged untilModel.save()
is called.GeneratedField
attributes on the model instance duringModel.full_clean()
, prior to calls toConstraint.validate()
, and irrespective of whether relevant constraints are present.The second option would allow further checks against the new
GeneratedField
value of the instance to be made during validation. On the other hand, the first option would leave the instance's attribute returning the value currently returned/stored by the database.Which would be best?