在 Django 中,ORM(Object Relational Mapping,對象關系映射) 是框架的核心之一。它允許你使用 Python 代碼來操作數據庫,而無需編寫原始 SQL 語句。Django ORM 不僅簡化了數據庫操作,還提升了代碼的可讀性、可維護性和安全性。
本文將帶你從基礎到進階,全面了解 Django ORM 的使用方式,包括模型定義、字段類型、查詢操作、聚合函數、關系映射、性能優化等內容。
一、什么是 Django ORM?
ORM 是一種編程技術,它將數據庫中的表映射為 Python 類,表中的行映射為類的實例,字段映射為類的屬性。
在 Django 中:
- 每個模型(Model)對應數據庫中的一張表;
- 每個模型實例對應表中的一條記錄;
- 每個模型類的屬性對應表中的字段。
優點:
- 跨數據庫兼容:支持多種數據庫(PostgreSQL、MySQL、SQLite、Oracle);
- 避免 SQL 注入:ORM 會自動處理參數化查詢;
- 提高開發效率:用 Python 代碼操作數據庫,無需寫 SQL;
- 結構清晰:模型定義清晰,易于維護。
二、定義模型(Model)
示例:定義一個博客文章模型
from django.db import modelsclass Author(models.Model):name = models.CharField(max_length=100)email = models.EmailField(unique=True)def __str__(self):return self.nameclass Post(models.Model):title = models.CharField(max_length=200)content = models.TextField()author = models.ForeignKey(Author, on_delete=models.CASCADE)published = models.BooleanField(default=True)created_at = models.DateTimeField(auto_now_add=True)updated_at = models.DateTimeField(auto_now=True)def __str__(self):return self.title
常見字段類型:
字段類型 | 說明 |
| 字符串字段,必須指定 |
| 長文本字段 |
| 整數 |
| 布爾值(True/False) |
| 時間日期字段, 自動設置創建時間, 自動更新時間 |
| 郵箱字段,自動驗證格式 |
| 外鍵,用于建立一對多關系 |
| 多對多關系 |
| 一對一關系 |
三、字段選項(Field Options)
字段可以設置各種選項,控制其行為:
選項 | 說明 |
| 允許該字段為 NULL(數據庫層面) |
| 表單驗證時允許為空(Django 層面) |
| 設置默認值 |
| 字段值必須唯一 |
| 字段的可讀名稱,用于管理界面 |
| 表單幫助信息 |
| 限制字段的取值范圍,如性別字段 |
示例:
GENDER_CHOICES = (('M', '男'),('F', '女'),
)class Profile(models.Model):gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
四、模型關系
Django ORM 支持三種主要的關系類型:
1. 一對一(OneToOneField)
class User(models.Model):username = models.CharField(max_length=100)class UserProfile(models.Model):user = models.OneToOneField(User, on_delete=models.CASCADE)bio = models.TextField()
2. 一對多(ForeignKey)
class Post(models.Model):author = models.ForeignKey(Author, on_delete=models.CASCADE)
3. 多對多(ManyToManyField)
class Tag(models.Model):name = models.CharField(max_length=30)class Post(models.Model):tags = models.ManyToManyField(Tag)
五、查詢操作(QuerySet)
Django ORM 提供了強大的查詢 API,可以使用鏈式調用構建復雜的查詢。
1. 基本查詢
Post.objects.all() # 獲取所有文章
Post.objects.get(id=1) # 獲取主鍵為 1 的文章(不存在會拋異常)
Post.objects.filter(title='Django') # 過濾標題為 Django 的文章
Post.objects.exclude(title='SQL') # 排除標題為 SQL 的文章
2. 查詢條件(Field Lookups)
條件 | 示例 | 說明 |
|
| 精確匹配 |
|
| 忽略大小寫匹配 |
|
| 包含字符串 |
|
| 忽略大小寫包含 |
|
| 大于 |
|
| 大于等于 |
|
| 小于 |
|
| 小于等于 |
|
| 在某個列表中 |
|
| 判斷是否為 NULL |
3. 排序與切片
Post.objects.order_by('title') # 按標題升序
Post.objects.order_by('-title') # 按標題降序
Post.objects.all()[:5] # 取前5條記錄
4. 聚合查詢(Aggregate)
from django.db.models import Count, Avg, Max, Min, SumPost.objects.aggregate(Avg('id')) # 平均值
Post.objects.aggregate(Max('id')) # 最大值
Post.objects.annotate(count=Count('author')) # 按作者統計文章數量
六、Meta 元類配置
通過 class Meta
可以配置模型的元信息:
class Post(models.Model):title = models.CharField(max_length=200)class Meta:db_table = 'blog_posts' # 自定義表名ordering = ['-created_at'] # 默認排序verbose_name = '博客文章'verbose_name_plural = '博客文章列表'
七、模型方法
你可以在模型中定義自定義方法,用于封裝業務邏輯:
class Person(models.Model):first_name = models.CharField(max_length=50)last_name = models.CharField(max_length=50)def full_name(self):return f"{self.first_name} {self.last_name}"
八、遷移(Migrations)
每次修改模型后,需要運行遷移命令更新數據庫結構:
# 生成遷移文件
python manage.py makemigrations# 應用遷移
python manage.py migrate
九、性能優化技巧
1. 使用 select_related()
(用于 ForeignKey)
Post.objects.select_related('author').all()
2. 使用 prefetch_related()
(用于 ManyToManyField)
Post.objects.prefetch_related('tags').all()
3. 使用 only()
和 defer()
Post.objects.only('title', 'author') # 只加載部分字段
Post.objects.defer('content') # 排除某些字段
4. 使用 exists()
判斷是否存在
Post.objects.filter(title='Django').exists()
十、總結
Django ORM 是一個強大而靈活的數據庫抽象層,它讓開發者可以用 Python 代碼操作數據庫,極大提升了開發效率和代碼可維護性。
本文我們講解了:
- ORM 的基本概念和優勢
- 如何定義模型、字段和關系
- 查詢操作(filter、exclude、order_by 等)
- 聚合與統計
- Meta 元類配置
- 模型方法
- 遷移命令
- 性能優化技巧
掌握 Django ORM 是使用 Django 構建 Web 應用的關鍵技能。接下來你可以深入學習:
- 自定義查詢(Raw SQL、extra)
- 數據庫函數(如 Concat、Substr)
- 使用事務(transaction)
- 使用數據庫索引優化查詢性能
十一、參考資料
Models | Django documentation | Django
QuerySet API reference | Django documentation | Django
LearnDjango | LearnDjango.com
Page not found | LearnDjango.com