skip to content

Model Classes

How a Django model maps to a table: field classes and options, relations and on_delete rules, Meta constraints, inheritance styles and custom fields. Interviewers test schema design in the ORM.

part ofDjangooverview, primer and where to startread it →
on this pageshow

explore

questions

page 1 of 2

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
open as a page

In Django 6.x, what primary key does a model get when it declares none, and how do DEFAULT_AUTO_FIELD and AppConfig.default_auto_field change it?

level: juniorimportance: must knowfreq 55%

basics

~10 s

Django adds an auto-incrementing id field. Its class comes from the app's AppConfig.default_auto_field if set, otherwise from the DEFAULT_AUTO_FIELD setting, which defaults to BigAutoField since Django 6.0 (AutoField before).

open as a page

In a Django model, what is the inner class Meta for, and which options does it typically hold?

level: juniorimportance: must knowfreq 60%

basics

~20 s

class Meta holds model-level options rather than fields: the table name (db_table), default ordering, human-readable names, indexes, constraints and a few behaviour switches. Django reads it when building the model's _meta; it never becomes a column.

open as a page

In a Django model, what does a ForeignKey's on_delete argument decide, and how do you choose a value for each relation?

level: juniorimportance: must knowfreq 74%

basics

~20 s

on_delete tells Django what to do with rows that reference an object when that object is deleted: delete them too (CASCADE), refuse the delete (PROTECT, RESTRICT), or rewrite their key (SET_NULL, SET_DEFAULT, SET()). It is required on every ForeignKey and OneToOneField.

open as a page

How do Django's TextChoices and IntegerChoices work on a model field, and does choices= stop invalid values from reaching the database?

level: middleimportance: must knowfreq 58%

basics

~20 s

TextChoices and IntegerChoices are enums whose members carry a stored value and a human label; pass the class as choices=. Choices are enforced by model validation and forms only, so save(), update() or raw SQL can still store any value.

open as a page

In Django, how would you model a Like that can point at a Photo, a Comment or a Post using GenericForeignKey?

level: middleimportance: must knowfreq 50%

basics

~20 s

Give Like a ForeignKey to ContentType, an object_id column holding the target's primary key, and a GenericForeignKey combining the two; add GenericRelation(Like) on Photo, Comment and Post for reverse access, and add the index yourself.

open as a page

In a Django custom Field subclass, what do from_db_value(), to_python(), get_prep_value() and get_db_prep_value() each do, and when is each called?

level: middleimportance: must knowfreq 42%

basics

~20 s

from_db_value() converts column values into Python objects whenever rows are loaded; to_python() converts form or fixture input during cleaning and deserialization; get_prep_value() turns a Python object into a query value; get_db_prep_value() adds any backend-specific conversion.

open as a page

In Django, how do you choose between abstract base, multi-table and proxy model inheritance for a car-rental fleet's vehicle types?

level: middleimportance: must knowfreq 62%

basics

~20 s

Choose by what the database must hold: an abstract base gives each vehicle type its own complete table, multi-table inheritance keeps a queryable Vehicle table joined one-to-one to each child, and a proxy changes behaviour on one existing table without new columns.

open as a page

In Django, what do Model.clean() and full_clean() do, and why doesn't save() call them?

level: middleimportance: must knowfreq 58%

basics

~10 s

full_clean() validates an instance: clean_fields(), then clean(), validate_unique() and validate_constraints(), raising one ValidationError. clean() is your hook for cross-field rules. save() never calls them, so code saving directly must validate itself.

open as a page

In Django, a WikiPage model generates its slug in an overridden save(); which write paths never run that code?

level: middleimportance: must knowfreq 66%

basics

~10 s

QuerySet.update(), bulk_create(), bulk_update(), raw SQL, loaddata fixtures and data migrations using historical models all skip an overridden save(). QuerySet.delete() and cascades likewise skip an overridden delete().

open as a page

In Django, how do you enforce at most one active subscription per user with Meta.constraints, and why not unique_together?

level: middleimportance: must knowfreq 55%

basics

~10 s

Add UniqueConstraint(fields=["user"], condition=Q(status="active"), name=...) to Meta.constraints. The database then allows many cancelled rows per user but only one active one. unique_together cannot take a condition and is the legacy option.

open as a page

In Django, what is the ContentType model, and what does ContentType.objects.get_for_model() give you?

level: juniorimportance: should knowfreq 30%

basics

~20 s

ContentType is the contenttypes app's registry: one row per installed model, identified by app_label and model name. get_for_model() returns that row for a model class or instance, creating it if missing and caching it in-process.

open as a page

In Django, when you write a custom MoneyField, what does the Field subclass do and what does the model attribute hold?

level: juniorimportance: should knowfreq 32%

basics

~20 s

A custom field usually means two classes: a value class such as Money that code works with, and a Field subclass that converts that value to and from its column. The model attribute holds the Money object; the field lives in Model._meta.

open as a page

In a Django model, what does setting abstract = True in the inner Meta class do, and when would you use it?

level: juniorimportance: should knowfreq 55%

basics

~20 s

It makes the model an abstract base class: Django creates no table and no manager for it, and every concrete subclass inherits its fields, managers and (unless overridden) its Meta in a complete table of its own.

open as a page

In a Django model, what do __str__ and get_absolute_url provide, and which parts of Django call them?

level: juniorimportance: should knowfreq 55%

basics

~20 s

str gives each instance a human-readable label, used by the admin, the shell and templates; the default is "WikiPage object (42)". get_absolute_url returns the object's canonical URL, used by redirect(), generic edit views, the admin's View on site link, sitemaps and feeds.

open as a page

In a Django model, which field options does the database enforce, and which does only model validation check?

level: middleimportance: should knowfreq 48%

basics

~10 s

The database enforces what reaches the schema: null=False (NOT NULL), unique=True (a unique constraint), CharField max_length (VARCHAR length) and db_default. blank, choices, validators and unique_for_date are checked only by full_clean() and forms.

open as a page

Why should a Django model store a menu item's price in a DecimalField rather than a FloatField, and what do max_digits and decimal_places control?

level: middleimportance: should knowfreq 50%

basics

~20 s

DecimalField maps to a fixed-precision numeric column and Python's decimal.Decimal, so 12.50 stays exact; FloatField uses binary floating point, which cannot represent most prices exactly. max_digits caps total digits and decimal_places the digits after the point.

open as a page

For a Django custom model field, how do you choose its database column type: db_type(), get_internal_type(), or subclassing a built-in field?

level: middleimportance: should knowfreq 25%

basics

~10 s

Subclass a built-in field when its column and validation already fit; return a built-in name from get_internal_type() to borrow its per-backend column type; override db_type(connection) only for a type Django lacks, branching on connection.vendor.

open as a page

Why does a Django custom model field need a correct deconstruct() method, and when must you override it?

level: middleimportance: should knowfreq 35%

basics

~20 s

Django's migrations record every field as the arguments needed to rebuild it, and deconstruct() supplies them as (name, path, args, kwargs). Override it whenever your init adds or forces arguments, so migrations can recreate the exact field.

open as a page

In a Django model, how does GeneratedField compute a line item's total, and what do its expression, output_field and db_persist arguments control?

level: middleimportance: should knowfreq 35%

basics

~20 s

GeneratedField declares a GENERATED ALWAYS column: expression is the database-side formula, output_field sets the column's type, and db_persist chooses a stored column (True) or a virtual one computed on read (False). Django never writes it.

open as a page

In Django, what can a proxy model declared with Meta.proxy = True change about its parent model, and what may it not add?

level: middleimportance: should knowfreq 42%

basics

~20 s

A proxy model reuses its parent's table and columns but may change Python-side behaviour: methods, str, default ordering, the default manager, and a separate admin and permissions. It may not add fields and must have exactly one concrete base.

open as a page

In Django, what does save(update_fields=[...]) change about the UPDATE statement, and which surprises come with it?

level: middleimportance: should knowfreq 45%

basics

~20 s

save(update_fields=[...]) writes only the named columns in an UPDATE, so other columns changed elsewhere are not overwritten. It forces an update, skips auto_now fields and derived fields not listed, and raises NotUpdated if no row matches.

open as a page

In Django 6.1, how do you declare a CheckConstraint in Meta.constraints, and on which code paths is it enforced?

level: middleimportance: should knowfreq 40%

basics

~20 s

Add models.CheckConstraint(condition=Q(...), name=...) to Meta.constraints. The database rejects any write that breaks it with IntegrityError, whatever the code path; full_clean() also checks it and raises ValidationError. The old check= keyword was removed in Django 6.0.

open as a page

In Django, which queries does Meta.ordering apply to, and what does a default ordering cost?

level: middleimportance: should knowfreq 44%

basics

~20 s

Meta.ordering adds an ORDER BY to every query on the model that does not call order_by(), including related managers and first()/last(). Aggregation queries with GROUP BY skip it. The cost is a sort on every such query.

open as a page

In Django, when does a ManyToManyField need an explicit through model, and how does it change adding and removing related rows?

level: middleimportance: should knowfreq 52%

basics

~20 s

Use a through model when the link itself carries data, such as an author's position and royalty share on a book. add(), create() and set() still work, but required link fields must come via through_defaults, and pair uniqueness is yours to declare.

open as a page

In Django, when do you choose OneToOneField over ForeignKey, and what does its reverse accessor do when no related row exists?

level: middleimportance: should knowfreq 48%

basics

~20 s

OneToOneField is a unique foreign key whose reverse side returns a single object instead of a manager. Use it when each row has at most one partner. When no partner exists, the reverse accessor raises RelatedObjectDoesNotExist.

open as a page

In Django 5.0+, how does a model field's default differ from db_default, and when would you choose db_default?

level: seniorimportance: should knowfreq 34%

basics

~20 s

default is computed by Python when an instance is created and leaves no DEFAULT on the column; db_default (Django 5.0+) puts a DEFAULT clause in the schema, so the database fills any INSERT that omits the column.

open as a page

showing 1–30 of 42