Django 模型与数据库操作:深入掌握 2.2 数据库操作 Django ORM(对象关系映射)是框架的核心优势之一,它将数据库操作抽象为 Python 对象操作,显著提升开发效率与代码可维护性。本章系统讲解 Django 数据库操作(CRUD)全链路实践,涵盖基础操作、高级查询、事务控制与性能优化四大维度,帮助开发者构建健壮、高效、可扩展的数据层。 2.2.1 准备工作:模型定义与环境配置 在执行数据库操作前,需确保模型已正确定义,数据库连接配置就绪,并完成迁移初始化。 模型定义示例( ) ✅ 关键优化说明: 为 和 字段添加 ,为高频查询字段建立数据库索引; 在 类中声明 ,使 默认按出版日期倒序排列; 添加 提升 Django Admin 可读性。
Django ORM(对象关系映射)是框架的核心优势之一,它将数据库操作抽象为 Python 对象操作,显著提升开发效率与代码可维护性。本章系统讲解 Django 数据库操作(CRUD)全链路实践,涵盖基础操作、高级查询、事务控制与性能优化四大维度,帮助开发者构建健壮、高效、可扩展的数据层。
在执行数据库操作前,需确保模型已正确定义,数据库连接配置就绪,并完成迁移初始化。
models.py)# myapp/models.py from django.db import models class Book(models.Model): title = models.CharField(max_length=200, db_index=True) author = models.CharField(max_length=100, db_index=True) publication_date = models.DateField() price = models.DecimalField(max_digits=5, decimal_places=2) is_available = models.BooleanField(default=True) class Meta: ordering = ['-publication_date'] verbose_name = "书籍" verbose_name_plural = "书籍" def __str__(self): return self.title
✅ 关键优化说明:
- 为
title和author字段添加db_index=True,为高频查询字段建立数据库索引;- 在
Meta类中声明ordering,使Book.objects.all()默认按出版日期倒序排列;- 添加
verbose_name提升 Django Admin 可读性。
settings.py)# settings.py import os from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', 'OPTIONS': { 'timeout': 20, # 防止 SQLite 锁等待超时 } } }
# 生成迁移文件 python manage.py makemigrations # 应用迁移,创建数据表 python manage.py migrate # (可选)验证模型是否注册成功 python manage.py showmigrations
💡 提示:首次运行
migrate后,Django 会自动创建auth、contenttypes、sessions等内置表,Book表将同步生成。
Django 提供两种主流创建方式,适用于不同业务场景。
Model.objects.create() —— 一步创建并保存适用于简单、确定性插入场景,代码简洁高效:
# 创建单条记录 book = Book.objects.create( title="Python 编程从入门到实践", author="Eric Matthes", publication_date="2015-11-26", price=59.00, is_available=True ) print(f"✅ 创建成功:《{book.title}》(ID: {book.id})")
⚠️ 注意:
create()方法不触发模型的save()信号(如pre_save/post_save),如需信号支持,请使用实例化+save()方式。
save() —— 灵活可控的创建流程适用于需预处理、校验或依赖信号的场景:
# 创建实例(未保存至数据库) book = Book( title="流畅的Python", author="Luciano Ramalho", publication_date="2015-07-16", price=79.00, is_available=True ) # 可在此处添加业务逻辑(如价格合规检查、作者标准化处理等) if book.price < 0: raise ValueError("价格不能为负数") # 保存并触发信号 book.save() print(f"✅ 保存成功:《{book.title}》(ID: {book.id})")
bulk_create() —— 高性能插入适用于导入大量数据(如 CSV 批量入库),显著减少数据库往返次数:
books_data = [ Book(title="Effective Python", author="Brett Slatkin", publication_date="2015-11-01", price=69.00), Book(title="Django for Beginners", author="William S. Vincent", publication_date="2018-08-15", price=49.99), Book(title="Two Scoops of Django", author="Daniel Greenfeld", publication_date="2020-02-20", price=54.99), ] # 批量插入(默认每批 100 条,可指定 batch_size) created_books = Book.objects.bulk_create(books_data, batch_size=100) print(f"✅ 批量创建 {len(created_books)} 条记录")
✅ 优势:相比循环调用
create(),bulk_create()可将 N 次插入压缩为 1 次 SQLINSERT语句,性能提升达 10 倍以上。
Django QuerySet 是惰性求值的数据库查询封装,支持链式调用与高效缓存。
all() 与惰性特性# 返回 QuerySet(尚未执行 SQL) books_qs = Book.objects.all() # 仅当遍历时才真正查询数据库 for book in books_qs: print(f"📖 {book.title} —— {book.author}") # QuerySet 可重复使用(已缓存结果) count = books_qs.count() # 不会再次查询
filter() 与字段查找(Lookups)| 查找类型 | 语法示例 | 说明 |
|---|---|---|
| 精确匹配 | filter(title="Python") |
字符串全等匹配 |
| 包含搜索 | filter(title__contains="Python") |
区分大小写 |
| 模糊包含 | filter(title__icontains="python") |
不区分大小写 |
| 范围查询 | filter(price__gte=50, price__lte=80) |
价格区间 [50, 80] |
| 日期查询 | filter(publication_date__year=2023) |
查询 2023 年出版书籍 |
| 空值判断 | filter(author__isnull=True) |
查找作者为空的记录 |
# 多条件组合(隐式 AND) recent_expensive_books = Book.objects.filter( publication_date__year__gte=2020, price__gt=60.00, is_available=True ).order_by('-publication_date') # 使用 __in 批量匹配 popular_authors = ["Eric Matthes", "Luciano Ramalho", "Brett Slatkin"] books_by_popular_authors = Book.objects.filter(author__in=popular_authors)
exclude()# 排除已下架书籍 available_books = Book.objects.exclude(is_available=False) # 等价于 Book.objects.filter(is_available=True)
get() 与安全替代方案# ⚠️ 危险:未捕获异常将导致 500 错误 try: book = Book.objects.get(title="流畅的Python") except Book.DoesNotExist: print("❌ 书籍不存在") except Book.MultipleObjectsReturned: print("❌ 找到多本同名书籍,请检查数据唯一性") # ✅ 推荐:使用 `first()` / `last()` 安全获取(返回 None 而非异常) book = Book.objects.filter(title="流畅的Python").first() if book: print(f"✅ 找到:《{book.title}》") else: print("❌ 未找到匹配书籍")
order_by() 与切片# 单字段排序(升序:字段名;降序:-字段名) books_by_price_desc = Book.objects.order_by('-price') # 多字段排序(先按作者升序,再按价格降序) books_sorted = Book.objects.order_by('author', '-price') # 分页:获取最贵的 3 本书 top_3_books = Book.objects.order_by('-price')[:3] # 获取第 2 页(每页 10 条):跳过前 10 条,取后 10 条 page_2_books = Book.objects.all()[10:20]
# ❌ N+1 查询:获取每本书的作者信息时触发 N 次额外查询 books = Book.objects.all() for book in books: print(f"{book.title} —— {book.author}") # 每次访问 author 触发一次查询 # ✅ 使用 select_related(适用于 ForeignKey / OneToOneField) books = Book.objects.select_related().all() # 预加载所有外键关联 # 或指定字段:select_related('author_profile') # ✅ 使用 prefetch_related(适用于 ManyToManyField / reverse ForeignKey) # (需配合自定义模型关系使用)
🔑 核心原则:
select_related使用JOIN一次查询;prefetch_related使用额外SELECT预加载,适合多对多场景。
save()# 获取并更新 book = Book.objects.get(id=1) book.price = 69.00 book.save() # 触发 pre_save / post_save 信号
QuerySet.update()# 直接执行 SQL UPDATE,不加载实例,不触发信号,性能极高 updated_count = Book.objects.filter( publication_date__year__lt=2010 ).update(is_available=False) print(f"✅ 批量下架 {updated_count} 本老书")
F() 表达式from django.db.models import F # 价格统一上调 5% Book.objects.all().update(price=F('price') * 1.05) # 库存增加:inventory = F('inventory') + 10 # 注意:F() 运算在数据库层面完成,避免竞态条件
delete()book = Book.objects.get(title="事务测试书籍 1") book.delete() # 触发 pre_delete / post_delete 信号 print("✅ 书籍已删除")
QuerySet.delete()# 批量清理下架书籍 deleted_count, _ = Book.objects.filter(is_available=False).delete() print(f"✅ 清理 {deleted_count} 条下架记录")
# 模型定义中显式声明级联行为(推荐) class Book(models.Model): # ... publisher = models.ForeignKey( 'Publisher', on_delete=models.CASCADE, # 删除出版社时自动删除其所有书籍 # on_delete=models.PROTECT, # 阻止删除(如有书籍存在) # on_delete=models.SET_NULL, # 设为 NULL(需 null=True) )
🛡️ 生产建议:关键业务表推荐使用软删除(添加
is_deleted字段 + 自定义管理器),避免数据不可逆丢失。
Q 对象组合from django.db.models import Q # OR 查询:作者是 A 或价格 < 50 q1 = Q(author="Eric Matthes") | Q(price__lt=50.00) books = Book.objects.filter(q1) # NOT 查询 + 复合条件 q2 = ~Q(author__in=["Eric Matthes", "Luciano Ramalho"]) books = Book.objects.filter(q2) # 混合使用:(A OR B) AND C q3 = (Q(author="Eric Matthes") | Q(author="Brett Slatkin")) & Q(is_available=True) books = Book.objects.filter(q3)
aggregate()from django.db.models import Avg, Max, Min, Sum, Count stats = Book.objects.aggregate( avg_price=Avg('price'), max_price=Max('price'), min_price=Min('price'), total_books=Count('id'), total_value=Sum('price') ) print(f""" 📊 图书统计: • 平均价格:¥{stats['avg_price']:.2f} • 最高价格:¥{stats['max_price']} • 总数量:{stats['total_books']} 本 • 总价值:¥{stats['total_value']:.2f} """)
annotate()from django.db.models import Avg, Count # 为每本书添加“同类作者平均价格”注解 books_with_author_avg = Book.objects.annotate( author_avg_price=Avg('author__price') # 假设 author 是 ForeignKey 到 Author 模型 ) # 统计每位作者的出书数量 author_book_counts = Book.objects.values('author').annotate( book_count=Count('id') ).order_by('-book_count') for item in author_book_counts: print(f"✍️ {item['author']}:{item['book_count']} 本")
transaction.atomic()from django.db import transaction try: with transaction.atomic(): # 所有操作在同一个事务中 book1 = Book.objects.create(title="事务内书籍1", price=29.99) book2 = Book.objects.create(title="事务内书籍2", price=39.99) # 模拟可能失败的操作 if book1.price + book2.price > 100: raise ValueError("总价超限,事务将回滚") print("✅ 事务提交:两本书籍创建成功") except ValueError as e: print(f"❌ 事务回滚:{e}")
✅ 事务特性:
atomic()是原子性保证的核心;- 支持嵌套(内层
atomic()在外层失败时自动回滚);- 生产环境务必对关键业务(如支付、库存扣减)使用事务。
| 优化方向 | 推荐方案 | 效果 |
|---|---|---|
| 查询效率 | 为 filter/order_by 字段添加 db_index=True |
查询速度提升 3–10 倍 |
| N+1 问题 | select_related()(正向外键)、prefetch_related()(反向/多对多) |
减少 90%+ 数据库查询 |
| 批量操作 | bulk_create()、bulk_update()、update() |
插入/更新性能提升 5–20 倍 |
| 缓存利用 | QuerySet 复用、values_list('id', flat=True) 减少内存占用 |
降低内存消耗与序列化开销 |
| SQL 优化 | 使用 explain() 分析慢查询(Book.objects.explain()) |
精准定位索引缺失或全表扫描 |
# 查看 Django 生成的 SQL(开发调试用) qs = Book.objects.filter(price__gt=50).order_by('-title') print(qs.query) # 输出原始 SQL # 数据库执行计划分析(支持 PostgreSQL/MySQL) print(qs.explain())
Django ORM 不仅是便捷的数据库封装,更是数据一致性、业务安全与系统性能的统一载体。本章系统覆盖:
Q 对象、聚合/注解、关联预加载,应对复杂业务逻辑;atomic() 保障关键操作原子性,级联策略明确数据生命周期;掌握这些能力,开发者可将 80% 的数据库交互转化为简洁、可读、可测试的 Python 代码,同时保有对底层 SQL 与数据库特性的完全掌控力。真正的工程效能,始于对 ORM 的深度理解与敬畏。
📌 核心口诀:
“先索引,再预加载;批量操作优先;事务兜底关键流;explain 验证每一查。”