在 Django 中,get()
和 filter()
是 QuerySet API 中用于检索数据的两个核心方法,它们的功能和使用场景有明显区别。以下是详细对比:
1. 核心区别
特性 | get() |
filter() |
---|---|---|
返回值 | 单个对象(模型实例) | 查询集(QuerySet,可迭代) |
数量限制 | 必须精确匹配1个对象 | 可以匹配0个、1个或多个对象 |
对象不存在时 | 抛出 DoesNotExist 异常 |
返回空查询集(不报错) |
多对象匹配时 | 抛出 MultipleObjectsReturned 异常 |
返回包含多个对象的查询集 |
链式调用 | 不支持(返回的是模型实例) | 支持(可继续添加过滤条件) |

2. 语法与示例
get()
的用法
python
# 获取 ID 为 1 的书(必须存在且唯一)
book = Book.objects.get(id=1)
# 等价的手动异常处理
try:
book = Book.objects.get(id=1)
except Book.DoesNotExist:
# 处理不存在的情况
pass
except Book.MultipleObjectsReturned:
# 处理多对象匹配的情况
pass
filter()
的用法
python
# 获取所有已发布的书(可能有0本或多本)
books = Book.objects.filter(status='published')
# 链式过滤:获取已发布且价格大于 50 的书
books = Book.objects.filter(status='published').filter(price__gt=50)
# 等价的单语句写法
books = Book.objects.filter(status='published', price__gt=50)
# 获取第一本书或 None(推荐替代 get() 的安全写法)
first_book = books.first() # 等价于 books[0] if books else None
3. 性能对比
get()
:直接查询单条记录,生成的 SQL 类似SELECT ... WHERE ... LIMIT 1
,理论上更高效。filter().first()
:生成的 SQL 是SELECT ... WHERE ... LIMIT 1
,与get()
几乎相同,但多了一步 Python 对象转换,性能损耗可忽略不计。
注意 :在查询条件唯一(如主键查询)时,两者性能接近;但 filter().first()
更安全。
4. 适用场景
推荐使用 get()
的场景
-
查询条件唯一(如通过主键或唯一键查询)。
-
对象必须存在,否则视为程序错误(如配置项、固定ID的系统数据)。
-
示例 :
pythonuser = User.objects.get(username='admin') # 管理员用户必须存在
推荐使用 filter()
的场景
-
查询条件不唯一(如按类别筛选商品)。
-
结果可能为空(如搜索功能)。
-
需要链式查询(如分页、排序、多条件组合)。
-
示例 :
python# 搜索功能(结果可能为空) books = Book.objects.filter(title__icontains='python') # 分页查询 books = Book.objects.filter(category='tech').order_by('-pub_date')[:10]
5. 常见错误案例
错误使用 get()
的场景
python
# 错误:title 可能不唯一,导致 MultipleObjectsReturned
book = Book.objects.get(title="Python")
# 正确:使用 filter().first()
book = Book.objects.filter(title="Python").first()
低效的 filter()
使用
python
# 低效:两次数据库查询
if Book.objects.filter(id=1).exists():
book = Book.objects.get(id=1) # 重复查询
# 高效:单次查询
book = Book.objects.filter(id=1).first()
6. 总结
场景 | 方法 |
---|---|
通过主键/唯一键获取单个对象 | get() (需确保存在) |
安全获取单个对象(不存在时返回 None) | filter().first() |
查询可能存在多个结果或空结果 | filter() |
需要链式查询(如分页、排序) | filter() |
建议 :优先使用 filter().first()
替代 get()
,除非你能绝对保证查询条件的唯一性和存在性。