一、Django ORM 常用字段類型
1. 基礎字段類型
字段類型 | 說明 | 示例 |
---|---|---|
CharField | 字符串字段,必須指定 max_length | name = models.CharField(max_length=50) |
IntegerField | 整數字段 | age = models.IntegerField() |
BooleanField | 布爾值字段 | is_active = models.BooleanField() |
DateField / DateTimeField | 日期/日期時間字段,auto_now_add=True 自動設置創建時間 | created_at = models.DateTimeField(auto_now_add=True) |
EmailField | 專用于郵箱的 CharField (自帶基礎格式驗證) | email = models.EmailField() |
TextField | 長文本字段(不限長度) | content = models.TextField() |
FileField / ImageField | 文件/圖片上傳字段(需 Pillow 庫支持 ImageField ) | avatar = models.ImageField(upload_to='avatars/') |
2. 關聯字段類型
字段類型 | 說明 | 示例 |
---|---|---|
ForeignKey | 外鍵(一對多關聯) | author = models.ForeignKey('Author', on_delete=models.CASCADE) |
OneToOneField | 一對一關聯(常用于擴展用戶模型) | profile = models.OneToOneField(User, on_delete=models.CASCADE) |
ManyToManyField | 多對多關聯(自動創建中間表) | tags = models.ManyToManyField('Tag') |
關鍵參數說明:
on_delete
: 關聯對象刪除時的行為(必填),常見選項:CASCADE
: 級聯刪除(默認)SET_NULL
: 設為null
(需字段允許null=True
)PROTECT
: 阻止刪除
related_name
: 反向查詢時的名稱(默認模型名_set
,如book_set
)
二、跨表引用技巧
1. 正向查詢(直接通過外鍵訪問)
# 模型定義
class Author(models.Model):name = models.CharField(max_length=100)class Book(models.Model):title = models.CharField(max_length=100)author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name="books")# 示例:查詢某本書的作者
book = Book.objects.get(id=1)
author_name = book.author.name # 直接通過外鍵訪問
2. 反向查詢(通過關聯模型反向訪問)
# 示例:查詢某作者的所有書籍
author = Author.objects.get(id=1)
books = author.books.all() # 使用 related_name 定義的名稱(默認是 book_set)
3. 跨表過濾(使用雙下劃線 __)
# 查詢所有書籍的作者名為 "魯迅" 的書籍
books = Book.objects.filter(author__name="魯迅")# 查詢作者出版過書籍數量大于 5 的作者
authors = Author.objects.annotate(book_count=Count('books')).filter(book_count__gt=5)
三、_
和 __
的使用技巧
1. 單下劃線 _
- 用途:用于關聯字段的數據庫列名或 ORM 內部操作。
- 示例:
# 訪問外鍵的數據庫列名(author_id) book = Book.objects.get(id=1) author_id = book.author_id # 直接獲取外鍵值(無需訪問關聯對象)# 查詢時直接使用字段名 Book.objects.filter(author_id=1)
2. 雙下劃線 __
- 用途:跨表查詢時連接關聯模型的字段(可鏈式跨多張表)。
- 示例:
# 查詢作者所在城市為 "北京" 的書籍 Book.objects.filter(author__city="北京")# 多級跨表:查詢書籍的作者的出版社名稱 Book.objects.filter(author__publisher__name="人民出版社")
3. 雙下劃線與查詢表達式結合
# 查詢價格大于 100 且作者年齡小于 30 的書籍
Book.objects.filter(price__gt=100, author__age__lt=30)# 查詢書名以 "Django" 開頭或作者郵箱包含 "@example.com"
from django.db.models import Q
Book.objects.filter(Q(title__startswith="Django") | Q(author__email__contains="@example.com"))
四、總結
核心技巧
-
字段類型選擇:
- 根據數據類型選擇合適字段(如
CharField
vsTextField
)。 - 關聯字段注意
on_delete
和related_name
的設置。
- 根據數據類型選擇合適字段(如
-
跨表查詢:
- 正向查詢:直接通過外鍵字段訪問關聯對象。
- 反向查詢:使用
related_name
或默認的模型名_set
。 - 復雜查詢:通過
__
跨表連接字段。
-
_
vs__
:_
用于數據庫列名或單級字段訪問(如author_id
)。__
用于跨表查詢(如author__name
)。
性能優化
- 使用
select_related
預加載外鍵數據(減少查詢次數):books = Book.objects.select_related('author').all() # 一次性加載作者信息
- 使用
prefetch_related
預加載多對多關系:authors = Author.objects.prefetch_related('books').all() # 預加載所有書籍
通過靈活組合這些技巧,可以高效操作 Django ORM 處理復雜的數據關系!
好的!反向查詢是 Django ORM 中通過關聯模型(比如外鍵的“被關聯方”)去訪問發起關聯的模型的關鍵操作。它讓跨表查詢更靈活,下面用詳細的示例和場景幫你徹底理解。
一、反向查詢的核心原理
假設有兩個模型:Author
(作者)和 Book
(書籍),通過外鍵關聯:
class Author(models.Model):name = models.CharField(max_length=100)class Book(models.Model):title = models.CharField(max_length=100)author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
- 正向查詢:從
Book
訪問Author
(直接通過外鍵字段author
)。 - 反向查詢:從
Author
訪問所有關聯的Book
對象(需要借助related_name
或默認的book_set
)。
二、反向查詢的兩種方式
1. 使用默認的 模型名_set
如果未設置 related_name
,Django 會自動生成反向查詢管理器,格式為:關聯模型名的小寫 + _set
。
# 假設 Book 模型的外鍵未設置 related_name
class Book(models.Model):author = models.ForeignKey(Author, on_delete=models.CASCADE)# 反向查詢:通過 author.book_set 訪問所有書籍
author = Author.objects.get(id=1)
books = author.book_set.all() # 獲取該作者的所有書籍
2. 使用自定義的 related_name
通過設置 related_name
,可以指定更直觀的反向查詢名稱:
class Book(models.Model):author = models.ForeignKey(Author, on_delete=models.CASCADE,related_name='books' # 自定義反向查詢名稱)# 反向查詢:通過 author.books 訪問所有書籍
author = Author.objects.get(id=1)
books = author.books.all() # 更直觀的命名
三、反向查詢的常見操作
1. 獲取關聯對象集合
# 查詢作者 "魯迅" 的所有書籍
author = Author.objects.get(name="魯迅")
books = author.books.all() # 返回 QuerySet
2. 過濾關聯對象
# 查詢作者 "魯迅" 的出版年份大于 2020 的書籍
books = author.books.filter(publish_year__gt=2020)
3. 創建新的關聯對象
# 為作者 "魯迅" 創建一本新書
new_book = author.books.create(title="狂人日記", publish_year=1918)
4. 統計關聯對象數量
# 統計作者 "魯迅" 的書籍數量
book_count = author.books.count()
四、反向查詢在跨表過濾中的使用
反向查詢結合雙下劃線 __
,可以在查詢條件中直接穿透關聯模型。
場景1:查詢所有寫過“小說”類書籍的作者
# 模型擴展:書籍增加分類字段
class Book(models.Model):CATEGORY_CHOICES = [('novel', '小說'),('tech', '科技'),]category = models.CharField(max_length=10, choices=CATEGORY_CHOICES)author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')# 反向查詢:直接通過 Author 模型過濾
authors = Author.objects.filter(books__category='novel').distinct()
books__category
:從Author
穿透到Book
的category
字段。distinct()
:避免重復作者(如果同一作者有多本小說)。
場景2:查詢書籍平均評分大于 4.5 的作者
from django.db.models import Avg# 模型擴展:書籍增加評分字段
class Book(models.Model):rating = models.FloatField(default=0)author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')# 使用 annotate + 反向查詢
authors = Author.objects.annotate(avg_rating=Avg('books__rating')
).filter(avg_rating__gt=4.5)
五、反向查詢的性能優化
1. 使用 prefetch_related
預加載數據
避免 N+1 查詢問題(遍歷作者時,每次訪問 author.books
都會觸發一次查詢):
# 未優化:觸發多次查詢
authors = Author.objects.all()
for author in authors:print(author.books.all()) # 每次循環觸發一次查詢# 優化后:一次性預加載所有作者的書籍
authors = Author.objects.prefetch_related('books').all()
for author in authors:print(author.books.all()) # 無額外查詢
2. 結合 select_related
和 prefetch_related
select_related
:用于外鍵(一對一、多對一)的預加載。prefetch_related
:用于多對多、反向查詢的預加載。
# 同時預加載作者和書籍的出版社(假設 Book 有外鍵到 Publisher)
authors = Author.objects.prefetch_related(Prefetch('books', queryset=Book.objects.select_related('publisher'))
).all()
六、總結:反向查詢的核心技巧
操作 | 代碼示例 | 說明 |
---|---|---|
基本反向查詢 | author.books.all() | 獲取所有關聯對象 |
過濾關聯對象 | author.books.filter(title__contains="Django") | 根據條件篩選關聯對象 |
跨表過濾 | Author.objects.filter(books__rating__gt=4) | 在查詢條件中使用反向關聯字段 |
聚合統計 | Author.objects.annotate(book_count=Count('books')) | 統計每個作者的書籍數量 |
預加載優化 | prefetch_related('books') | 減少數據庫查詢次數 |
關鍵點:
- 始終優先使用
related_name
自定義反向查詢名稱(代碼更清晰)。 - 在復雜查詢中靈活使用雙下劃線
__
穿透關聯模型。 - 大數據量時用
prefetch_related
或select_related
優化性能。
通過反向查詢,你可以輕松實現從“一”對“多”或“多對多”關系的反向導航,讓數據關聯操作更加靈活高效!