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

新增数据有两种方式: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() # 获取张三的所有书
多对多关系:比如Book
和Category
(书籍分类)是多对多,用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