在 Django 中,get()
和 filter()
是 QuerySet API 中用于檢索數據的兩個核心方法,它們的功能和使用場景有明顯區別。以下是詳細對比:
1. 核心區別
特性 | get() | filter() |
---|---|---|
返回值 | 單個對象(模型實例) | 查詢集(QuerySet,可迭代) |
數量限制 | 必須精確匹配1個對象 | 可以匹配0個、1個或多個對象 |
對象不存在時 | 拋出 DoesNotExist 異常 | 返回空查詢集(不報錯) |
多對象匹配時 | 拋出 MultipleObjectsReturned 異常 | 返回包含多個對象的查詢集 |
鏈式調用 | 不支持(返回的是模型實例) | 支持(可繼續添加過濾條件) |
2. 語法與示例
get()
的用法
# 獲取 ID 為 1 的書(必須存在且唯一)
book = Book.objects.get(id=1)# 等價的手動異常處理
try:book = Book.objects.get(id=1)
except Book.DoesNotExist:# 處理不存在的情況pass
except Book.MultipleObjectsReturned:# 處理多對象匹配的情況pass
filter()
的用法
# 獲取所有已發布的書(可能有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的系統數據)。
- 示例:
user = User.objects.get(username='admin') # 管理員用戶必須存在
推薦使用 filter()
的場景
- 查詢條件不唯一(如按類別篩選商品)。
- 結果可能為空(如搜索功能)。
- 需要鏈式查詢(如分頁、排序、多條件組合)。
- 示例:
# 搜索功能(結果可能為空) books = Book.objects.filter(title__icontains='python')# 分頁查詢 books = Book.objects.filter(category='tech').order_by('-pub_date')[:10]
5. 常見錯誤案例
錯誤使用 get()
的場景
# 錯誤:title 可能不唯一,導致 MultipleObjectsReturned
book = Book.objects.get(title="Python")# 正確:使用 filter().first()
book = Book.objects.filter(title="Python").first()
低效的 filter()
使用
# 低效:兩次數據庫查詢
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()
,除非你能絕對保證查詢條件的唯一性和存在性。