2.2 数据库操作


文档摘要

Django 模型与数据库操作:深入掌握 2.2 数据库操作 Django ORM(对象关系映射)是框架的核心优势之一,它将数据库操作抽象为 Python 对象操作,显著提升开发效率与代码可维护性。本章系统讲解 Django 数据库操作(CRUD)全链路实践,涵盖基础操作、高级查询、事务控制与性能优化四大维度,帮助开发者构建健壮、高效、可扩展的数据层。 2.2.1 准备工作:模型定义与环境配置 在执行数据库操作前,需确保模型已正确定义,数据库连接配置就绪,并完成迁移初始化。 模型定义示例( ) ✅ 关键优化说明: 为 和 字段添加 ,为高频查询字段建立数据库索引; 在 类中声明 ,使 默认按出版日期倒序排列; 添加 提升 Django Admin 可读性。

Django 模型与数据库操作:深入掌握 2.2 数据库操作

Django ORM(对象关系映射)是框架的核心优势之一,它将数据库操作抽象为 Python 对象操作,显著提升开发效率与代码可维护性。本章系统讲解 Django 数据库操作(CRUD)全链路实践,涵盖基础操作、高级查询、事务控制与性能优化四大维度,帮助开发者构建健壮、高效、可扩展的数据层。

2.2.1 准备工作:模型定义与环境配置

在执行数据库操作前,需确保模型已正确定义,数据库连接配置就绪,并完成迁移初始化。

模型定义示例(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

关键优化说明

  • titleauthor 字段添加 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 会自动创建 authcontenttypessessions 等内置表,Book 表将同步生成。

2.2.2 创建数据(CREATE)

Django 提供两种主流创建方式,适用于不同业务场景。

2.2.2.1 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() 方式。

2.2.2.2 实例化 + 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})")

2.2.2.3 批量创建: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 次 SQL INSERT 语句,性能提升达 10 倍以上。

2.2.3 读取数据(READ)

Django QuerySet 是惰性求值的数据库查询封装,支持链式调用与高效缓存。

2.2.3.1 全量查询:all() 与惰性特性

# 返回 QuerySet(尚未执行 SQL) books_qs = Book.objects.all() # 仅当遍历时才真正查询数据库 for book in books_qs: print(f"📖 {book.title} —— {book.author}") # QuerySet 可重复使用(已缓存结果) count = books_qs.count() # 不会再次查询

2.2.3.2 条件过滤: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)

2.2.3.3 排除数据:exclude()

# 排除已下架书籍 available_books = Book.objects.exclude(is_available=False) # 等价于 Book.objects.filter(is_available=True)

2.2.3.4 获取单条记录: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("❌ 未找到匹配书籍")

2.2.3.5 排序与分页: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]

2.2.3.6 关联数据预加载:解决 N+1 查询问题

# ❌ 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 预加载,适合多对多场景。

2.2.4 更新数据(UPDATE)

2.2.4.1 单对象更新:save()

# 获取并更新 book = Book.objects.get(id=1) book.price = 69.00 book.save() # 触发 pre_save / post_save 信号

2.2.4.2 批量更新:QuerySet.update()

# 直接执行 SQL UPDATE,不加载实例,不触发信号,性能极高 updated_count = Book.objects.filter( publication_date__year__lt=2010 ).update(is_available=False) print(f"✅ 批量下架 {updated_count} 本老书")

2.2.4.3 数据库级字段计算:F() 表达式

from django.db.models import F # 价格统一上调 5% Book.objects.all().update(price=F('price') * 1.05) # 库存增加:inventory = F('inventory') + 10 # 注意:F() 运算在数据库层面完成,避免竞态条件

2.2.5 删除数据(DELETE)

2.2.5.1 单对象删除:delete()

book = Book.objects.get(title="事务测试书籍 1") book.delete() # 触发 pre_delete / post_delete 信号 print("✅ 书籍已删除")

2.2.5.2 批量删除:QuerySet.delete()

# 批量清理下架书籍 deleted_count, _ = Book.objects.filter(is_available=False).delete() print(f"✅ 清理 {deleted_count} 条下架记录")

2.2.5.3 级联删除与软删除策略

# 模型定义中显式声明级联行为(推荐) 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 字段 + 自定义管理器),避免数据不可逆丢失。

2.2.6 高级查询技巧

2.2.6.1 复杂逻辑: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)

2.2.6.2 聚合统计: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} """)

2.2.6.3 注解增强: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']} 本")

2.2.7 数据库事务管理

显式事务: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() 在外层失败时自动回滚);
  • 生产环境务必对关键业务(如支付、库存扣减)使用事务。

2.2.8 性能优化最佳实践

优化方向 推荐方案 效果
查询效率 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())

2.2.9 总结:构建健壮高效的数据层

Django ORM 不仅是便捷的数据库封装,更是数据一致性、业务安全与系统性能的统一载体。本章系统覆盖:

  • CRUD 全流程实践:从单条创建到批量删除,兼顾灵活性与性能;
  • 高级查询能力Q 对象、聚合/注解、关联预加载,应对复杂业务逻辑;
  • 事务与数据安全atomic() 保障关键操作原子性,级联策略明确数据生命周期;
  • 生产级优化策略:索引设计、批量操作、N+1 治理,直击性能瓶颈。

掌握这些能力,开发者可将 80% 的数据库交互转化为简洁、可读、可测试的 Python 代码,同时保有对底层 SQL 与数据库特性的完全掌控力。真正的工程效能,始于对 ORM 的深度理解与敬畏。

📌 核心口诀
“先索引,再预加载;批量操作优先;事务兜底关键流;explain 验证每一查。”


发布者: 作者: 转发
评论区 (0)
U