skip to content

In a Django model, what is the difference between null=True and blank=True, and why avoid null=True on a CharField?

level: juniorimportance: must knowfreq 82%

answer

  1. one is about the column
  2. the other is about validation
  3. two ways to say 'no data'
  4. the unique-and-blank exception

basics

~20 s

null=True lets the database column store NULL; blank=True lets validation (forms and full_clean) accept an empty value. On CharField and TextField, Django's convention is blank=True with an empty string, so there is one 'no data' value, not two.

solid answer

~40 s

`null` is about the **database**: `null=True` makes the column nullable and stores `None` as `NULL`, while the default `null=False` adds `NOT NULL`. `blank` is about **validation**: `blank=True` lets a `ModelForm` or `full_clean()` accept an empty value, while the default makes the field required. For string fields the convention is `blank=True` alone, so an optional description is stored as `""`; adding `null=True` gives two meanings of 'empty', `NULL` and `""`, and every query has to check both. The exception is a `CharField` with `unique=True` and `blank=True`: several blank rows would all store `""` and collide, so add `null=True`, and a `ModelForm` then saves empty input as `NULL`. Non-string optional fields — a spice level, a date — need **both** `null=True` and `blank=True`, since they have no empty value other than `NULL`.

code

python · 8 lines
python
from django.db import models


class MenuItem(models.Model):
    name = models.CharField(max_length=120)
    description = models.TextField(blank=True)  # optional text: "" means none
    spice_level = models.PositiveSmallIntegerField(null=True, blank=True)
    sku = models.CharField(max_length=20, unique=True, null=True, blank=True)

go deeper

for a junior

State that null is about the database column and blank about validation, and that optional text uses blank=True with an empty string.

for a middle

Explain the two-empties problem with null=True on strings, the unique-plus-blank exception, and why optional numbers need both options.

for a senior

Spot data drift from mixed NULL and empty strings in existing tables and plan the clean-up and migration that settle on one representation.

for a principal

Set a team convention for optional values across models and APIs so NULL, empty string and absent fields mean the same thing everywhere.

## Two options, two layers A Django model field has two independent switches that people often confuse: | option | layer | default | effect | |---|---|---|---| | `null` | database | `False` | `True` makes the column nullable, so Python `None` is stored as SQL `NULL` | | `blank` | validation | `False` | `True` lets forms and `Model.full_clean()` accept an empty value | `null=False` produces a `NOT NULL` column, so the database itself rejects `NULL`. `blank` produces no SQL at all: it is one of the attributes Django treats as not affecting the schema, so toggling it creates a migration that runs no SQL. Changing `null`, by contrast, alters the column. ## The menu item example ```python from django.db import models class MenuItem(models.Model): name = models.CharField(max_length=120) description = models.TextField(blank=True) spice_level = models.PositiveSmallIntegerField(null=True, blank=True) sku = models.CharField(max_length=20, unique=True, null=True, blank=True) ``` - **`name`** — required in forms (`blank=False`) and `NOT NULL` in the database. - **`description`** — optional in forms; an empty description is stored as `""`. The column stays `NOT NULL`. - **`spice_level`** — optional, and an integer has no "empty" value, so it needs `null=True` for the column and `blank=True` for the form. - **`sku`** — optional *and* unique: the special case described below. ## Why not null=True on strings Django's documented convention is that string-based fields use the **empty string** as their "no data" state. With `null=True` on a `CharField` or `TextField` there are two possible empties, `NULL` and `""`, which causes real bugs: - `filter(description="")` misses the `NULL` rows, and `filter(description__isnull=True)` misses the `""` rows, so reports and exports need both conditions. - Different write paths produce different empties — a form, an import script, the admin — and the data drifts. - Templates and API responses must treat `None` and `""` alike. One backend note: Oracle stores the empty string as `NULL` regardless of this option. ## The exception: unique and blank A unique column rejects two equal values, and `""` equals `""`. If `sku` were `unique=True, blank=True` without `null=True`, the second item saved without a SKU would violate the unique constraint. Databases do not treat `NULL`s as equal in a unique constraint by default, so the fix is `null=True`. A `ModelForm` then converts an empty input to `None` for that field — model `CharField`s with `null=True` build their form field with `empty_value=None` — so blank SKUs are stored as `NULL` and do not collide. ## blank without null on non-string fields `blank=True` with `null=False` on, say, an `IntegerField` means the form accepts an empty value that the column cannot store. Unless something supplies a value — a `default`, or the model's `clean()` — saving it fails with an `IntegrityError` from the `NOT NULL` column. The documentation calls this out: that combination requires you to fill the missing value yourself. ## Cleaning up a column that already has both Inherited tables often hold both empties. The fix is a two-step change: 1. A data migration that normalises the rows, for example `MenuItem.objects.filter(description__isnull=True).update(description="")`. 2. A schema migration that removes `null=True`, turning the column back to `NOT NULL`. Order matters: removing `null=True` first would fail on the existing `NULL` rows. Until both steps ship, queries for "no description" must use `Q(description="") | Q(description__isnull=True)`. ## Rules of thumb 1. Optional text: `blank=True`, no `null`. 2. Optional number, date or boolean: `null=True, blank=True`. (`BooleanField(null=True)` replaced `NullBooleanField`, removed in Django 4.0.) 3. Optional and unique text: `unique=True, null=True, blank=True`. 4. Required anything: leave both at their defaults. Remember that `blank` is enforced only where validation runs — `ModelForm`s, the admin and explicit `full_clean()` calls — while `null=False` is enforced by the database on every write.

  • What happens if an IntegerField has blank=True but not null=True and the form is left empty?
    Validation accepts the empty value, but the column is `NOT NULL`, so saving `None` raises an `IntegrityError` unless something supplies a value first, such as a `default` or the model's `clean()`. Optional numbers normally need `null=True` as well.
  • Does changing blank on a field require a database change?
    No. `blank` only affects validation, and Django treats it as a non-database attribute, so the migration it generates runs no SQL. Changing `null` alters the column's nullability.

saying these in an interview costs you the question

  • blank=True makes the database column nullable
  • null=True makes the field optional in forms too
  • every optional CharField should also set null=True
  • Django treats NULL and the empty string as the same value in filters
  • an optional IntegerField only needs blank=True