skip to content

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%

answer

  1. who computes the value
  2. Python at instantiation, database at INSERT
  3. rows written outside Django
  4. DatabaseDefault on unsaved instances
  5. default wins when both are set

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.

solid answer

~50 s

`default` is a Python value or callable applied in `Model.__init__` when no value is given; the schema carries no `DEFAULT`, so raw SQL or another service inserting a row gets nothing (or a `NOT NULL` error). `db_default` (Django 5.0+) is a literal or database expression — `Now()`, `Pi()` — written into the column's `DEFAULT`; Django omits the field from the `INSERT` and the database computes it. On an unsaved instance the attribute is a `DatabaseDefault` placeholder; after `save()` Django reads the real value back where the backend supports `RETURNING`, and otherwise defers the field so it is loaded on first access. `db_default` cannot reference other fields, and when both are set, `default` wins for instances created in Python while `db_default` still serves outside inserts and migrations. Choose it for database-clock timestamps and tables that other systems write to.

code

python · 4 lines
python
item = MenuItem(name="Pho")
print(type(item.created).__name__)  # DatabaseDefault: not computed yet
item.save()
print(item.created)  # the timestamp the database computed

go deeper

for a junior

Know that default is filled in by Python and db_default by the database, and that callables like list are used for mutable defaults.

for a middle

Explain DatabaseDefault on unsaved instances, precedence when both are set, and what migrations do with a Python default.

for a senior

Pick db_default when other systems insert rows or the database clock matters, and account for the read-back behaviour on each backend.

for a principal

Decide which defaults are part of the schema contract shared with other writers and which stay application behaviour, and document the split.

## Two different places a default can live | | `default` | `db_default` (Django 5.0+) | |---|---|---| | computed by | Python, when the instance is built | the database, during the `INSERT` | | can be | any value or callable | a literal or database expression | | column `DEFAULT` | none | yes | | applies to raw SQL inserts | no | yes | | value on an unsaved instance | the computed value | a `DatabaseDefault` placeholder | | can use other fields | a callable can do anything in Python | no — `F("start") + 50` is invalid | ## How default behaves `default` is applied in `Model.__init__` when a field is not given a value: a callable, such as `dict` or `timezone.now`, is called once per new instance. Nothing about it reaches the table. When a migration adds a column with a `default`, Django uses the value to fill existing rows and then drops the column `DEFAULT` again. Consequences: - rows inserted by raw SQL, another service or a database tool get no value, and a `NOT NULL` column rejects them; - a timestamp from `default=timezone.now` comes from the **application server's** clock at instantiation, not at commit; - defaults must not be mutable objects — `default=[]` would share one list — so use a callable such as `list`. ## How db_default behaves ```python from django.db import models from django.db.models.functions import Now class MenuItem(models.Model): name = models.CharField(max_length=120) is_available = models.BooleanField(db_default=True) created = models.DateTimeField(db_default=Now()) ``` 1. The migration writes `DEFAULT true` and `DEFAULT CURRENT_TIMESTAMP`-style clauses into the columns. 2. `MenuItem(name="Pho")` holds a `DatabaseDefault` object in `created` and `is_available` until it is saved; `full_clean()` skips validating those placeholders. 3. On `save()`, Django leaves those columns to the database's `DEFAULT`, and the database computes the values. 4. In Django 6.1, on backends that can return columns from an `INSERT` (PostgreSQL, SQLite, Oracle, MariaDB), the computed values are read back into the instance immediately; on MySQL the fields are marked deferred and fetched from the database on first access. Rules for the expression itself: literals and database functions are allowed, but it **cannot reference other fields or models**, and system checks reject expressions a backend cannot use as a default (`fields.E011`, `fields.E012`). ## When both are set If a field has both, **`default` takes precedence for instances created in Python**, so the ORM sends the Python value. `db_default` still sits on the column and is used for inserts outside the ORM and when a migration adds the field. This pairing suits a column that ORM code and legacy scripts both write. ## Choosing db_default Reach for `db_default` when: - **Other writers exist** — imports, SQL scripts, other services — and the table must still get a sensible value. - **You want the database clock** — `db_default=Now()` records when the database created the row, consistent across application servers. - **The default belongs to the schema** — documented in the table, visible to DBAs and reporting tools. Keep `default` when: - the value needs Python logic, the current request or other fields; - the value is a per-instance mutable object (`default=list`); - code needs the real value before saving, for example to display a form's initial state. ## Switching an existing field Changing `default=True` to `db_default=True` on an existing field produces an `AlterField` migration that adds the `DEFAULT` clause to the column. Existing rows keep their values; only future inserts that omit the column are affected. Review callers that read the attribute before saving, because they will now see a `DatabaseDefault` instead of `True` unless you keep `default` as well. ## Pitfalls - Reading `item.created` before `save()` returns a `DatabaseDefault`, not a datetime — do not format it in templates. - On MySQL, the first read of a `db_default` field after `save()` costs a query. - `db_default` is not the same as `GeneratedField`, which computes a column from other columns on every write; that belongs to generated columns.

  • Why can't db_default be F('base_price') * 2?
    A column `DEFAULT` is evaluated by the database without access to the row's other values, and Django's documentation states that database defaults cannot reference other fields or models. A value derived from other columns needs a `GeneratedField` or Python logic in `save()`.
  • What does a model instance hold in a db_default field before it is saved?
    A `DatabaseDefault` object, when the field has no Python `default` and no value was assigned. It tells Django to let the database supply the value at `INSERT`; the real value appears on the instance after `save()`.

default is a pre-filled form handed out at the counter: whatever the clerk wrote is what gets filed. db_default is a stamp the records office applies to any form that arrives with the box empty — including forms mailed in by other departments.

saying these in an interview costs you the question

  • default=... also sets a DEFAULT clause on the column
  • db_default can compute a value from another field with F()
  • when both are set, db_default wins for objects created in Python
  • an unsaved instance already holds the db_default value
  • default=timezone.now records the database server's time