Filter concepts by levelShowing all levels.

Django · Section 12

`null` vs `blank`

Level
intermediate
Read
8 min
Concepts
1

null is a database-level setting (can the column store SQL NULL); blank is a validation-level setting (can a form or full_clean() leave the field empty) — independent of each other, and usually needed together except on CharField/TextField, where Django's own convention is to use blank=True alone and let "" be the one and only empty value.

What is true here

  1. null=True affects only the database column — it has no effect on form validation.
  2. blank=True affects only form/full_clean() validation — it has no effect on what the database column allows.
  3. CharField/TextField should avoid null=True — "" is already the string type's own empty value, and adding NULL as a second one is redundant.
  4. DateField/ForeignKey/IntegerField and other non-text types need null=True AND blank=True together for a genuinely optional field.
  5. The one exception: a CharField with unique=True and blank=True needs null=True too, to avoid a unique-constraint violation between multiple blank submissions.

What you will be able to do

  • Explain the database-vs-validation distinction between null and blank without hesitation
  • Choose the correct null/blank combination for a text field versus a non-text field
  • Recognize the unique=True + blank=True exception that requires null=True even on a CharField

The distinction

Two independent settings, easy to conflate — one about the database, one about validation.

null vs blank

coreintermediate

null is database-level: null=True lets a column store SQL NULL. blank is validation-level: blank=True lets a form/full_clean() accept an empty value. They are independent — setting one does not set the other, and both are usually needed together for a genuinely optional field.

Think of it as

null answers "what can the DATABASE COLUMN hold" — blank answers "what can a FORM leave empty." For a CharField/TextField, Django's own convention is to never need null=True at all: an empty string ("") is already the string type's own "nothing here" value, so allowing NULL too just creates two different ways to mean the same thing (redundant, and a source of `if value` vs `if value is not None` bugs). A DateField or ForeignKey has no such empty value of its own — NULL is the only way those types can represent "nothing here," so null=True is the normal, correct choice for an optional field of those types.

python
subtitle = models.CharField(max_length=200, blank=True)   # "" for empty, never NULL
published_at = models.DateField(null=True, blank=True)     # NULL for empty

What we're doing: Make a text field and a date field both genuinely optional, using the correct null/blank combination for each type.

articles/models.pypython
class Article(models.Model):
    title = models.CharField(max_length=200)
    subtitle = models.CharField(max_length=200, blank=True)
    published_at = models.DateField(null=True, blank=True)
3
subtitle has no null=True — an unset subtitle is stored as "" (empty string), the string type's own natural "nothing here" value.
4
published_at needs BOTH — a DateField has no empty-but-valid date, so NULL (via null=True) is the only way to represent "not yet published," and blank=True is what lets a form leave it unset.

Why this works: The two fields need different treatment because of what each type CAN represent as "empty" on its own — a string already has "" for that; a date has nothing analogous, so it borrows NULL from the database layer instead. Using null=True on subtitle too would just create a second, redundant "empty" state ("" and NULL both meaning "no subtitle"), one more thing every reader of this code has to account for.

Setting null=True on a CharField "just in case," without blank=True

Wrong

python
subtitle = models.CharField(max_length=200, null=True)   # blank=True missing

Better

python
subtitle = models.CharField(max_length=200, blank=True)   # no null=True needed

What you see: A form built from this model still marks subtitle as required — leaving it empty fails validation — even though the database column itself would happily accept NULL. Separately, code now has to check both `if article.subtitle` AND `article.subtitle is not None` to mean the same thing.

Why: null only ever affects the database column, never form/full_clean() validation — blank is the ONLY setting that makes a field optional in a form, so null=True alone does nothing to relax that requirement. And because CharField already has "" as its own empty value, adding null=True on top creates two different representations of "no subtitle" that every reader and every query now has to handle.

null (database) vs blank (validation) are independent axes
title
required, no NULL — the normal default
subtitle (CharField)
blank=True alone — "" is the empty value
published_at (DateField)
needs BOTH — no empty date exists
  • title: blank=False (required), null=False (NOT NULL) — required, no NULL — the normal default
  • subtitle (CharField): blank=True (form may skip), null=False (NOT NULL) — blank=True alone — "" is the empty value
  • published_at (DateField): blank=True (form may skip), null=True (may store NULL) — needs BOTH — no empty date exists

null vs blank — what each actually controls

null vs blank — what each actually controls
Aspectnullblank
Layerdatabasevalidation (forms, full_clean())
DefaultFalse — NOT NULLFalse — required
CharField/TextField recommendationavoid, except unique=True + blank=TrueTrue, for an optional field
DateField/ForeignKey/etc. recommendationTrue, for an optional fieldTrue, for an optional field

Together

python
class Article(models.Model):
    subtitle = models.CharField(max_length=200, blank=True)              # no null=True
    published_at = models.DateField(null=True, blank=True)               # both
    editor = models.ForeignKey("auth.User", null=True, blank=True, on_delete=models.SET_NULL)

Remember: null is database-level (can the column be NULL); blank is validation-level (can a form leave it empty) — independent settings, usually needed TOGETHER for a non-text optional field, but text fields should use blank=True alone.

See also: models · text and numeric fields · primary keys and field options

Advertisement