In Django 5.0+, how does a model field's default differ from db_default, and when would you choose db_default?
answer
- who computes the value
- Python at instantiation, database at INSERT
- rows written outside Django
- DatabaseDefault on unsaved instances
- default wins when both are set
basics
~20 sdefault 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 linesitem = MenuItem(name="Pho")
print(type(item.created).__name__) # DatabaseDefault: not computed yet
item.save()
print(item.created) # the timestamp the database computedgo deeper
Know that default is filled in by Python and db_default by the database, and that callables like list are used for mutable defaults.
Explain DatabaseDefault on unsaved instances, precedence when both are set, and what migrations do with a Python default.
Pick db_default when other systems insert rows or the database clock matters, and account for the read-back behaviour on each backend.
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