#30610 closed Cleanup/optimization (duplicate)
Model.full_clean() doesn't prevetn invalid (null) values when blank=True.
Reported by: | Keryn Knight | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Consider the following model definition (ignoring the merits of it):
class Example(models.Model): txt = models.TextField(blank=True, null=False)
I'd expect to be able to do:
x = Example(txt=None) x.full_clean()
which should raise a ValidationError
because None is explicitly not a valid value for the field (null=False
) - but it doesn't, so subsequently doing x.save()
will raise IntegrityError
when the database (sqlite3, postgresql, I'd assume the same for mysql/mariadb) attempts to do the insert, with something like:
IntegrityError: NOT NULL constraint failed: testing_example.txt
(sqlite)
IntegrityError: null value in column "txt" violates not-null constraint
(postgresql)
I think it's down to
- if
blank=True
thenModel.clean_fields()
short circuits becauseEMPTY_VALUES
includesNone
- if
blank=False
it doesn't short-circuit and instead falls intoField.validate()
where the null check happens before the blank check, so the ValidationError is correctly raised thatThis field cannot be null
Tested against master @ 54dcfbc36780054d39299bfd1078938e5dd4e839, encountered in staging environment in 1.11, but it looks like it goes back to at least 2010 (commit 2f9853b2dc90f30317e0374396f08e3d142844d2)
There is this comment before bailing out early:
# Skip validation for empty fields with blank=True. The developer # is responsible for making sure they have a valid value.
This is specious reasoning. Blank is not so super-special that it should deserve throwing actual validation out of the window and into the mental gymnastics necessary to decide whether or not you can actually try and save something that ostensibly passed validation, according to both the code and the intent therein.
Change History (2)
comment:1 by , 5 years ago
Resolution: | → duplicate |
---|---|
Status: | new → closed |
Summary: | Model.full_clean() can ignore invalid (null) values which should raise ValidationError, because of blank=True short-circuiting → Model.full_clean() doesn't prevetn invalid (null) values when blank=True. |
comment:2 by , 5 years ago
Ah, didn't find that when searching Trac, sorry.
Perhaps it's worth pointing out that commenting out (just to see what happens) if f.blank and raw_value in f.empty_values: continue
only seems to cause one test to fail (test_validation_with_empty_blank_field
) and whilst it may be related to this, it doesn't look it at a glance.
Duplicate of #22224.