db_default 是 django 5.0 新增字段参数,由数据库而非 python 层生成默认值,不参与 insert values,依赖数据库 default 表达式;default 则由 django 在 python 层计算并写入 sql。

什么是 db_default,它和 default 有啥区别?
db_default 是 Django 5.0 新增的字段参数,用于让数据库(而非 Python 层)生成默认值。它不触发 ORM 的字段预填充逻辑,也不会出现在 INSERT 语句的 VALUES 子句中,而是依赖数据库自身的 DEFAULT 表达式(如 CURRENT_TIMESTAMP、uuid_generate_v4() 或自定义函数)。这和 default 完全不同:default 是 Python 值或可调用对象,在模型实例化或 save() 时由 Django 计算并写入 SQL;而 db_default 把默认逻辑彻底下推到数据库,连 INSERT 都不带这个字段。
什么时候该用 db_default 而不是 default?
适用于以下场景:
- 需要数据库级一致性:比如多个应用或直接 SQL 写入时,都必须走同一套默认逻辑
- 依赖数据库特性:如 PostgreSQL 的
gen_random_uuid()、MySQL 的NOW(3)、SQL Server 的GETDATE() - 避免 ORM 层时间偏差:用
default=timezone.now会在请求进入 Django 时就计算时间,而db_default="CURRENT_TIMESTAMP"是执行 INSERT 时刻由数据库决定 - 提升批量插入性能:省去 Python 层计算 + SQL 参数绑定开销
怎么在模型字段里正确设置 db_default?
注意三点:类型匹配、数据库支持、迁移行为。
- 字符串值(如
"CURRENT_TIMESTAMP")会被原样写入 CREATE TABLE 的 DEFAULT 子句,**必须确保语法与目标数据库兼容**;PostgreSQL 区分带引号的字符串字面量和函数调用,db_default="NOW()"才对,db_default="NOW"会报错 - 可传
models.Expression,例如db_default=Func(Value('public'), function='lower'),但要注意该表达式必须能被compiler.compile()渲染为合法 SQL 片段 - 首次添加含
db_default的字段时,Django 迁移会自动加DEFAULT子句;但修改已有字段的db_default不会自动更新数据库约束——得手动写RunSQL迁移 - SQLite 对 DEFAULT 支持较弱(仅接受字面量),复杂表达式会静默失效,上线前务必在目标库验证
示例:
from django.db import models <p>class Article(models.Model): title = models.CharField(max_length=200) slug = models.SlugField( db_default="gen_random_uuid()", # PostgreSQL 扩展函数 editable=False, ) created_at = models.DateTimeField( db_default="CURRENT_TIMESTAMP", # 注意:PostgreSQL 写法,MySQL 用 "CURRENT_TIMESTAMP()" editable=False, )</p>
容易踩的坑:迁移、查询、ORM 行为变化
db_default 不影响查询,但会影响你对“空值”的预期和调试方式:
- 字段没设
null=True,又没在 INSERT 时显式赋值,数据库按 DEFAULT 填值——但 Django ORM 查询结果里你看不出这个值是 Python 填的还是 DB 填的 -
Model.objects.create()不会触发db_default字段的任何 Python 侧动作,但如果该字段同时设了default和db_default,default仍会生效(优先级更高),容易误以为 DB 在起作用 - 使用
bulk_create()时,db_default字段若未显式提供值,PostgreSQL/MySQL 会正常走 DEFAULT;但 SQLite 可能全填 NULL,导致 NOT NULL 约束失败 - 测试时用
TestCase启动内存 SQLite,db_default很可能不工作,建议单元测试改用TransactionTestCase并连接真实数据库实例
最常被忽略的一点:字段加了 db_default 后,如果后续想改成由 Django 控制默认值,不能只删掉参数——旧数据库表里的 DEFAULT 约束还在,得额外执行 ALTER TABLE ... ALTER COLUMN ... DROP DEFAULT,否则两边逻辑打架。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











