pin_drop当前位置:知识文库 ❯ 图文

Django ORM查询详解 - 数据库操作与优化完整指南

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详解

常用查询方法

方法 说明 返回值
all() 查询所有记录 QuerySet
filter(**kwargs) 条件过滤 QuerySet
exclude(**kwargs) 排除条件 QuerySet
get(**kwargs) 获取单个对象 Model实例
first()/last() 第一条/最后一条 Model实例或None
count() 计数 int
exists() 是否存在 bool
order_by() 排序 QuerySet
values() 返回字典列表 QuerySet[dict]
values_list() 返回元组列表 QuerySet[tuple]
create(**kwargs) 创建并保存 Model实例
bulk_create() 批量创建 列表
update(**kwargs) 批量更新 int(影响行数)

常用查找类型(双下划线查询)

查找类型 说明 示例
exact 精确匹配 name__exact='Django'
iexact 不区分大小写 name__iexact='django'
contains 包含 title__contains='Python'
startswith 以...开头 name__startswith='Py'
gt/gte 大于/大于等于 price__gt=100
lt/lte 小于/小于等于 price__lt=50
in 在列表中 id__in=[1,2,3]
range 范围 price__range=(10,100)
isnull 是否为空 desc__isnull=True
year/month/day 日期字段查找 created__year=2024

四、高级查询技术

示例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_relatedprefetch_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()}")

查询优化方式对比

优化方式 说明 适用场景
select_related JOIN查询,一次获取 ForeignKey、OneToOneField
prefetch_related 两次查询,Python端合并 ManyToManyField、反向ForeignKey
only() 只查询指定字段 只需部分字段,减少数据传输
defer() 延迟加载指定字段 排除大字段(如TextField)
iterator() 流式遍历,不缓存 大数据量遍历,减少内存

六、实际应用场景

  • 文章列表查询:结合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除外)。

标签: Django ORM 数据库查询 QuerySet 性能优化 聚合查询

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Django中间件详解 - 请求响应钩子系统完整指南 下一篇: Django Migration迁移详解 - 数据库版本控制完整指南

poll相关推荐