Django ORM数据库操作实战指南:查询、更新与优化全流程

快速上手:Django ORM的基础操作

咱们先从最常用的增删改查说起——这些是Django ORM的“基本功”,学会了就能应付80%的简单场景。

Django ORM数据库操作实战指南:查询、更新与优化全流程

新增数据有两种方式:create()save()create()更简洁,直接传递字段参数就能返回实例;save()需要先创建对象再手动保存,适合需要先处理逻辑的场景:

# 方式1:create()一键新增(推荐)
from myapp.models import Book
book = Book.objects.create(title="Django实战", author="张三", price=59.9)

# 方式2:save()手动保存(适合需要预处理的情况)
book = Book(title="Python进阶", author="李四")
book.price = 69.9  # 可以在这里加逻辑,比如计算折扣
book.save()

删除数据delete(),支持单条或批量删除:

# 删除单条数据
book = Book.objects.get(id=1)
book.delete()

# 批量删除(谨慎使用!)
Book.objects.filter(author="张三").delete()

修改数据有两种思路:update()批量更新(不触发save()信号),或save()单条更新(触发信号):

# 批量更新:update()(高效,适合批量修改)
Book.objects.filter(author="张三").update(price=65.9)  # 所有张三的书涨价到65.9

# 单条更新:save()(适合需要触发信号或复杂逻辑)
book = Book.objects.get(id=2)
book.price = 79.9
book.save()  # 会触发pre_save和post_save信号

查询数据是基础中的基础,常用方法有all()(查所有)、filter()(条件查询)、get()(查单条,不存在会抛异常):

# 查所有数据
all_books = Book.objects.all()

# 条件查询:filter()(返回QuerySet,支持多个条件)
cheap_books = Book.objects.filter(price__lt=60, author="张三")  # 张三的书且价格<60

# 查单条数据:get()(必须返回1条,否则抛DoesNotExist或MultipleObjectsReturned)
book = Book.objects.get(title="Django实战")

QuerySet进阶:让查询更高效

QuerySet是Django ORM的核心——它是“延迟执行”的(直到需要结果时才会访问数据库),而且支持链式调用。学会这些技巧,能让你的查询更灵活。

链式调用是QuerySet的“灵魂”,可以把多个条件组合起来,代码更清晰:

# 组合条件:先过滤作者,再排除高价书,最后按出版日期排序
qs = Book.objects.filter(author="张三").exclude(price__gt=70).order_by("-publish_date")

延迟执行是QuerySet的性能优势——比如下面的代码,只有当print(len(qs))时才会真正查询数据库:

qs = Book.objects.filter(author="张三")  # 没查询数据库
print(qs)  # 没查询(返回QuerySet对象描述)
print(len(qs))  # 此时才会执行SQL查询

切片与取值:QuerySet支持Python切片语法,但要注意——切片是前闭后开,而且[:5]会生成LIMIT 5的SQL,[1:3]会生成LIMIT 2 OFFSET 1

# 取前5条:生成LIMIT 5
top5_books = Book.objects.all()[:5]

# 取第2到第4条(索引1-3):生成LIMIT 3 OFFSET 1
some_books = Book.objects.all()[1:4]

values与values_list:如果只需要部分字段,用这两个方法能减少数据传输量(避免加载整个实例):

# values():返回字典列表(键是字段名)
book_dicts = Book.objects.filter(author="张三").values("title", "price")
# 结果:[{"title": "Django实战", "price": 59.9}, ...]

# values_list():返回元组列表(更节省内存)
book_tuples = Book.objects.filter(author="张三").values_list("title", "price")
# 结果:[("Django实战", 59.9), ...]

# 如果只需要一个字段,可以加flat=True(返回一维列表)
book_titles = Book.objects.filter(author="张三").values_list("title", flat=True)
# 结果:["Django实战", "Python进阶", ...]

关联表处理:外键与多对多关系

实际开发中,表不可能孤立——外键(ForeignKey)、多对多(ManyToManyField)是常有的事。Django ORM帮你封装了这些关联,不用写JOIN语句也能轻松处理。

外键关系:比如Book模型有一个外键author指向Author模型,咱们可以通过book.author直接获取作者,反向通过author.book_set.all()获取作者的所有书:

# 正向查询:通过Book查Author
book = Book.objects.get(id=1)
author_name = book.author.name  # 直接访问外键字段

# 反向查询:通过Author查Book(Django自动生成book_set)
author = Author.objects.get(name="张三")
author_books = author.book_set.all()  # 获取张三的所有书

多对多关系:比如BookCategory(书籍分类)是多对多,用add()remove()clear()处理关联:

# 给书籍添加分类
book = Book.objects.get(id=1)
category = Category.objects.get(name="编程")
book.categories.add(category)  # 添加关联

# 移除分类
book.categories.remove(category)

# 清空所有分类
book.categories.clear()

# 查询书籍的所有分类
book_categories = book.categories.all()

性能优化:避免ORM踩坑

Django ORM好用,但如果不注意优化,容易写出“慢查询”。咱们来说说最常见的几个坑和解决方法。

坑1:N+1查询——这是最常见的性能问题!比如你查询所有书籍,然后循环访问book.author.name,会执行1次Book查询+N次Author查询(N是书籍数量)。解决方法是用select_related()(外键/一对一)或prefetch_related()(多对多/反向外键):

# 优化前:N+1查询(慢!)
books = Book.objects.all()
for book in books:
    print(book.author.name)  # 每次循环都查一次Author表

# 优化后:select_related()(JOIN查询,只查1次)
books = Book.objects.select_related("author").all()
for book in books:
    print(book.author.name)  # 无额外查询

# 多对多关系用prefetch_related()
books = Book.objects.prefetch_related("categories").all()
for book in books:
    print(book.categories.all())  # 只查2次(Book和Category)

坑2:不必要的字段加载——如果只需要几个字段,用only()defer()减少数据传输:

# 只加载title和price字段(其他字段不加载)
books = Book.objects.only("title", "price").all()

# 不加载content字段(适合大字段,比如文章内容)
books = Book.objects.defer("content").all()

坑3:批量操作不用bulk方法——循环save()delete()很慢,用bulk_create()bulk_update()批量处理:

# 批量新增:bulk_create(比循环save快10倍以上)
books = [
    Book(title="Book1", author="Author1", price=39.9),
    Book(title="Book2", author="Author2", price=49.9),
    Book(title="Book3", author="Author3", price=59.9),
]
Book.objects.bulk_create(books)  # 只执行1次SQL插入

# 批量更新:bulk_update(需要指定更新的字段)
books = Book.objects.filter(author="张三")
for book in books:
    book.price += 5  # 涨价5元
Book.objects.bulk_update(books, ["price"])  # 批量更新price字段

实战技巧:解决常见问题

最后咱们聊聊开发中常遇到的“小问题”,用这些技巧能快速解决。

问题1:获取或创建数据——避免重复创建,用get_or_create()

# get_or_create:存在则获取,不存在则创建
book, created = Book.objects.get_or_create(
    title="Django实战",  # 唯一条件
    defaults={"author": "张三", "price": 59.9}  # 不存在时的默认值
)
print(created)  # True表示新建,False表示已存在

问题2:处理日期查询——用__year__month__day等字段查找:

from django.utils import timezone
current_year = timezone.now().year
# 查询今年出版的书
this_year_books = Book.objects.filter(publish_date__year=current_year)

问题3:查询结果去重——用distinct(),比如查询包含“编程”或“技术”分类的书,避免重复:

# 去重查询:distinct()
books = Book.objects.filter(categories__name__in=["编程", "技术"]).distinct()

最后想说的话

Django ORM的核心是“用Python代码代替SQL”,它帮我们屏蔽了数据库的差异(比如MySQL和PostgreSQL的语法不同),但也需要我们了解它的底层逻辑——比如QuerySet的延迟执行、select_related的JOIN原理。

其实最好的学习方法就是“动手试”:写一段查询代码,然后用print(qs.query)看看生成的SQL是什么样的——这能帮你快速理解ORM的工作方式。

比如你写了Book.objects.filter(price__lt=60).select_related("author"),用print(qs.query)会输出:

SELECT "myapp_book"."id", "myapp_book"."title", "myapp_book"."author_id", "myapp_book"."price", "myapp_author"."id", "myapp_author"."name" FROM "myapp_book" INNER JOIN "myapp_author" ON ("myapp_book"."author_id" = "myapp_author"."id") WHERE "myapp_book"."price" < 60

这样你就能清楚地看到ORM做了什么,也能更快地优化查询。

希望这篇指南能帮你真正掌握Django ORM——它不是“银弹”,但绝对是Django开发者的“神兵利器”!

原创文章,作者:,如若转载,请注明出处:https://zube.cn/archives/186

(0)

相关推荐