Opened 4 months ago
Last modified 4 months ago
#35671 closed Cleanup/optimization
Field.null=False on string-based fields behaves inconsistently with the typical usage of Field.null. — at Version 1
Reported by: | Clifford Gama | Owned by: | |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 5.1 |
Severity: | Normal | Keywords: | Field.null; IntegrityError; NotNullConstraint; Field.default |
Cc: | Clifford Gama | 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 )
My concern is with the usage of Field.null=False
, which differs from its expected practical application, rather than just its technical function.
When Field.null=False
and Field.default
is not set for string-based fields—such as CharField
, TextField
, and SlugField
—Field.null
does not raise the expected IntegrityError: NOT NULL constraint failed
when a value is not provided for the field.
Django saves empty strings for these fields, and since the database does not (always?) interpret an empty string as NULL, they are accepted without raising the IntegrityError
. This behavior is not clearly documented and is inconsistent with the typical usage of Field.null
as a NOT NULL constraint.
The [documentation](https://docs.djangoproject.com/en/5.1/ref/models/fields/#django.db.models.Field.null) on Field.null
specifies:
Avoid using null on string-based fields such as CharField and TextField. If a string-based field has null=True, that means it has two possible values for “no data”: NULL and the empty string. In most cases, it’s redundant to have two possible values for “no data;” the Django convention is to use the empty string, not NULL.
What is not specified here or in the documentation for Field.default
is that Django effectively sets the empty string as the default for these string-based fields when none is provided. If you wish to truly disallow empty values for those fields, you need to set Field.default=None
and null=False
.
Since Django relies on the database to raise IntegrityError
s when a required field is not provided, it is inconsistent that Django does not treat the empty string as “no data” (i.e., NULL) in this context or that they use the empty string as “no data” when the database will interpret it as actual data.
The issue is particularly evident when a model instance is created using the model Manager's create()
and get_or_create()
methods or by direct instantiation.