get() 用于查询唯一记录,查无结果抛 DoesNotExist,查多结果抛 MultipleObjectsReturned;应仅在业务确保条件唯一时使用,否则用 filter().first() 更安全。

用 get() 查单条数据,必须确保结果唯一
get() 的设计目标就是「查且仅查一条」。它不像 filter() 返回 QuerySet,而是直接返回模型实例——前提是数据库里真有且只有一条匹配记录。如果查不到,抛 DoesNotExist;如果查到多条,抛 MultipleObjectsReturned。这两个异常都继承自 ObjectDoesNotExist,但类型不同,捕获时得注意。
常见错误现象:get() 在开发环境跑得好好的,上线后突然 500,日志里是 MultipleObjectsReturned —— 很可能是因为没加唯一约束(比如漏了 unique=True 或数据库索引),导致脏数据累积。
- 只在业务逻辑明确「该条件必然对应唯一记录」时才用
get(),例如查id=123、查username='alice'(且username字段已设unique=True) - 避免用
get()查非唯一字段,比如status='pending'或created_at__date=today - 如果只是想「取第一个匹配项」,用
first()更安全,它不抛异常,没结果就返回None
捕获 DoesNotExist 时别漏掉具体模型名
Django 不提供泛用的 DoesNotExist 类,每个模型都有自己的异常子类,比如 User.DoesNotExist、Order.DoesNotExist。直接写 except DoesNotExist: 会报 NameError。
使用场景:用户访问 /user/999 这种带 ID 的详情页,ID 不存在时要返回 404,而不是 500。
- 正确写法:
except User.DoesNotExist:或except order_model.DoesNotExist:(如果模型是动态导入的) - 想统一处理多个模型?可以用
except ObjectDoesNotExist:,它是所有DoesNotExist异常的父类 - 别用
except Exception:吞掉异常——这会掩盖MultipleObjectsReturned等真正该暴露的问题
get() 和 filter().first() 性能几乎没差别,但语义差很多
底层 SQL 都是 SELECT ... LIMIT 1,所以性能不用纠结。关键在语义和错误反馈方式:
-
get()表达「我认定这里必须有且仅有一个」,违反预期就该中断流程并告警 -
filter(...).first()表达「我只要一个,有没有都行」,适合宽松查询场景,比如推荐位取最新一篇草稿 - ORM 层不会因为用了
first()就跳过校验——它仍会执行完整查询再截取第一条,所以不能靠它绕过数据一致性问题
示例:User.objects.filter(email=email).first() 返回 None 是正常路径;User.objects.get(email=email) 抛异常才是正常路径。
测试时容易忽略的边界:空字符串、None、软删除字段
get() 对参数不做预过滤,传进去什么就拼什么 SQL。常见踩坑点:
- 前端传空字符串
''当作 ID 查询,User.objects.get(id='')会转成WHERE id = '',可能意外命中某条id被设为空字符串的脏数据 - 字段允许
null=True,但用get(status=None)实际生成的是WHERE status IS NULL,不是= NULL,这点没问题;但若误写成get(status='None')就完全跑偏了 - 用了软删除(如
is_deleted=False)却忘了在get()条件里加上,结果查出已被逻辑删除的记录
复杂点在于:这些都不是 Django 的 bug,而是你对输入源、数据状态和查询意图之间的一致性没兜住。写 get() 前,先问自己一句——这个条件,在当前数据状态下,真的能保证唯一且存在吗?


















