pin_drop当前位置:知识文库 ❯ 图文
Django ORM查询详解 - 数据库操作与优化完整指南
一、ORM概述
Django ORM(Object-Relational Mapping)是Django框架的核心组件之一,它提供了一种将Python对象映射到数据库表的机制。通过Model.objects管理器,开发者可以使用纯Python代码完成数据库的创建、查询、更新和删除(CRUD)操作,无需编写原始SQL语句。
ORM不仅简化了数据库操作,还提供了跨数据库兼容性——同一段ORM代码可以在SQLite、MySQL、PostgreSQL等不同数据库上运行。此外,Django ORM还支持复杂的过滤、排序、聚合、注解等高级查询功能,满足绝大多数业务场景的需求。
小贴士
虽然ORM能覆盖大部分场景,但对于极其复杂的SQL查询(如多层嵌套子查询、窗口函数等),可以使用Model.objects.raw()执行原始SQL。
二、基本语法与CRUD操作
所有ORM操作都从Model.objects管理器开始。以下是四种基本操作的语法:
代码示例
from myapp.models import MyModel
# 查询(Read)
MyModel.objects.all() # 查询所有记录
MyModel.objects.filter(field=value) # 条件查询
MyModel.objects.get(field=value) # 获取单个对象
# 创建(Create)
MyModel.objects.create(field=value)
# 更新(Update)
MyModel.objects.filter(field=value).update(field=new_value)
# 删除(Delete)
MyModel.objects.filter(field=value).delete()
三、查询API详解
常用查询方法
常用查找类型(双下划线查询)
四、高级查询技术
示例1:基本CRUD操作
代码示例
from myapp.models import Article
# 创建
article = Article.objects.create(
title='Django教程',
content='Django是Python Web框架',
status='published'
)
print(f"创建: {article.title}, ID: {article.id}")
# 查询所有
articles = Article.objects.all()
print(f"总数: {articles.count()}")
# 条件查询
published = Article.objects.filter(status='published')
print(f"已发布: {published.count()}")
# 获取单个
article = Article.objects.get(id=1)
print(f"获取: {article.title}")
# 更新(批量)
Article.objects.filter(id=1).update(views=100)
# 更新(实例)
article.views += 1
article.save()
# 删除
Article.objects.filter(status='draft').delete()
示例2:Q对象与F对象
Q对象用于构建复杂的OR查询和组合条件。F对象用于引用模型字段的值,可以在数据库层面进行字段间的运算,避免将数据取回Python端处理。
代码示例
from myapp.models import Article
from django.db.models import Q, F
# Q对象:复杂OR查询
articles = Article.objects.filter(
Q(title__contains='Python') | Q(title__contains='Django')
)
print(f"Python或Django: {articles.count()}")
# Q对象组合AND和OR
articles = Article.objects.filter(
Q(status='published') & (Q(title__icontains='python') | Q(title__icontains='django'))
)
# F对象:引用字段进行更新
from django.db.models import F
Article.objects.update(views=F('views') + 1)
# F对象比较两个字段
Article.objects.filter(published_date__gt=F('created_date'))
示例3:聚合与注解
聚合(aggregate)对整个QuerySet进行统计计算,返回字典。注解(annotate)为QuerySet中的每个对象添加一个计算字段,返回增强后的QuerySet。
代码示例
from django.db.models import Count, Avg, Max, Min
from myapp.models import Article, Category
# 聚合:对整个表进行统计
stats = Article.objects.aggregate(
avg_views=Avg('views'),
max_views=Max('views'),
min_views=Min('views'),
total=Count('id'),
)
print(f"统计: {stats}")
# 输出: {'avg_views': 150.5, 'max_views': 1000, 'min_views': 10, 'total': 200}
# 注解:为每个分类添加文章数量
categories = Category.objects.annotate(
article_count=Count('article')
)
for cat in categories:
print(f" {cat.name}: {cat.article_count}篇")
# 排序 + 注解:找出文章最多的分类
top_category = Category.objects.annotate(
article_count=Count('article')
).order_by('-article_count').first()
print(f"最多文章的分类: {top_category.name} ({top_category.article_count}篇)")
五、关联查询与性能优化
关联查询是ORM中最容易引发性能问题的场景。理解select_related和prefetch_related的区别,是编写高效ORM代码的关键。
代码示例
from myapp.models import Article, Category, Tag
# 正向查询(通过外键)
article = Article.objects.first()
print(f"分类: {article.category.name}") # 会触发额外查询(N+1问题)
# select_related:优化外键查询(使用SQL JOIN,一次查询)
articles = Article.objects.select_related('category').all()
for article in articles:
print(f" {article.title} - {article.category.name}") # 无额外查询
# prefetch_related:优化多对多查询(两次独立查询,Python端关联)
articles = Article.objects.prefetch_related('tags').all()
for article in articles:
tags = [t.name for t in article.tags.all()]
print(f" {article.title}: {tags}")
# 跨关系查询(双下划线语法)
articles = Article.objects.filter(category__name='Python')
print(f"Python分类文章: {articles.count()}")
查询优化方式对比
六、实际应用场景
-
文章列表查询:结合filter()、order_by()、分页器实现支持筛选、排序的列表页
-
数据统计仪表盘:使用aggregate()计算平均值、最大值、总数等指标
-
关联数据展示:使用select_related和prefetch_related优化文章详情页的分类、标签加载
七、注意事项
注意:QuerySet是惰性求值的,只有在遍历、切片、len()、list()等操作时才真正执行SQL。可以通过
str(queryset.query)查看生成的SQL。
注意:get()找不到对象会抛出DoesNotExist异常,找到多个会抛出MultipleObjectsReturned异常。不确定结果数量时,优先使用filter().first()。
注意:select_related用于外键和一对一关系(使用JOIN),prefetch_related用于多对多和反向关系(使用两次独立查询)。
注意:大量数据遍历时使用iterator()减少内存占用,它会逐条获取数据而不缓存整个QuerySet。
八、练习题
练习1
编写查询代码:查找2024年发布的、浏览量大于100的文章,按浏览量降序排列。
练习2
编写查询代码:统计每个分类下的文章数量,并找出文章数量最多的分类。
常见问题
filter()和get()有什么区别?
filter()始终返回QuerySet(可能为空),不会抛异常;get()返回单个Model实例,如果找不到对象会抛出DoesNotExist异常,找到多个会抛出MultipleObjectsReturned异常。
什么是QuerySet的惰性求值?
QuerySet创建时不会立即执行SQL,只有在真正需要数据时才执行查询(如遍历、len()、list()、bool()等)。这使得可以链式调用多个filter()而不会产生多次数据库查询。
select_related和prefetch_related如何选择?
select_related用于外键和一对一关系,通过SQL JOIN在一次查询中获取关联数据;prefetch_related用于多对多和反向关系,执行两次独立查询然后在Python端合并结果。两者可以同时使用。
如何查看ORM生成的SQL语句?
可以通过str(queryset.query)查看SQL语句。也可以在settings.py中配置LOGGING,或在Django shell中使用from django.db import connection; print(connection.queries)查看历史查询。
bulk_create和逐条create有什么区别?
bulk_create使用单条INSERT语句批量插入,性能远高于逐条create。但bulk_create不会调用模型的save()方法和信号(signals),默认也不返回主键(PostgreSQL除外)。
本文涉及AI创作
内容由AI创作,请仔细甄别