跳到主要内容

Django 复杂查询

在Django中,模型是与数据库交互的核心。通过Django的ORM(对象关系映射),我们可以使用Python代码来执行复杂的数据库查询,而无需编写原始的SQL语句。本文将介绍如何在Django中执行复杂查询,包括过滤、排序、聚合、注解以及使用Q对象和F表达式。

1. 过滤查询

Django的ORM提供了强大的过滤功能,允许我们根据特定条件从数据库中检索数据。最常用的方法是使用 filter()exclude()

示例:过滤查询

假设我们有一个 Book 模型,其中包含 titleauthorpublished_date 字段。

python
from django.db import models

class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=100)
published_date = models.DateField()

我们可以使用 filter() 方法来获取所有在2020年之后出版的书籍:

python
books = Book.objects.filter(published_date__year__gt=2020)

输出

python
<QuerySet [<Book: Book object (1)>, <Book: Book object (2)>]>
提示

filter() 方法返回的是一个 QuerySet,它表示满足条件的数据库记录集合。你可以进一步对这个 QuerySet 进行操作,比如排序、切片等。

2. 排序查询

在Django中,我们可以使用 order_by() 方法对查询结果进行排序。

示例:排序查询

假设我们想按出版日期对书籍进行排序:

python
books = Book.objects.order_by('published_date')

如果你想按降序排序,可以在字段名前加上 -

python
books = Book.objects.order_by('-published_date')

3. 聚合查询

Django提供了 aggregate() 方法,允许我们对查询结果进行聚合操作,比如计算平均值、总和、最大值等。

示例:聚合查询

假设我们想计算所有书籍的平均出版年份:

python
from django.db.models import Avg

average_year = Book.objects.aggregate(Avg('published_date__year'))

输出

python
{'published_date__year__avg': 2021.5}
备注

aggregate() 方法返回的是一个字典,其中键是聚合字段的名称,值是聚合结果。

4. 注解查询

注解(Annotation)允许我们在查询时为每个对象添加额外的字段。这些字段可以是计算字段、聚合字段等。

示例:注解查询

假设我们想为每本书添加一个字段,表示该书是否是在2020年之后出版的:

python
from django.db.models import Case, When, Value, BooleanField

books = Book.objects.annotate(
is_recent=Case(
When(published_date__year__gt=2020, then=Value(True)),
default=Value(False),
output_field=BooleanField(),
)
)

输出

python
<QuerySet [<Book: Book object (1)>, <Book: Book object (2)>]>
警告

注解字段不会保存到数据库中,它们只在查询时存在。

5. 使用Q对象进行复杂查询

Django的 Q 对象允许我们构建复杂的查询条件,比如 ANDORNOT 操作。

示例:使用Q对象

假设我们想查找所有在2020年之后出版且作者为 "John Doe" 的书籍:

python
from django.db.models import Q

books = Book.objects.filter(Q(published_date__year__gt=2020) & Q(author='John Doe'))

输出

python
<QuerySet [<Book: Book object (1)>]>
注意

Q 对象可以组合多个条件,但要注意逻辑运算符的使用。& 表示 AND| 表示 OR~ 表示 NOT

6. 使用F表达式进行字段比较

Django的 F 表达式允许我们在查询中引用模型的字段值,通常用于字段之间的比较。

示例:使用F表达式

假设我们想查找所有出版年份与作者出生年份相同的书籍:

python
from django.db.models import F

books = Book.objects.filter(published_date__year=F('author__birth_year'))

输出

python
<QuerySet [<Book: Book object (1)>]>
提示

F 表达式非常适合用于字段之间的比较或更新操作。

7. 实际案例

假设我们正在开发一个图书馆管理系统,需要实现以下功能:

  1. 查找所有在2020年之后出版且评分高于4.5的书籍。
  2. 计算每本书的平均评分,并按评分从高到低排序。

实现

python
from django.db.models import Avg, Q

# 查找所有在2020年之后出版且评分高于4.5的书籍
books = Book.objects.filter(Q(published_date__year__gt=2020) & Q(rating__gt=4.5))

# 计算每本书的平均评分,并按评分从高到低排序
books_with_avg_rating = Book.objects.annotate(avg_rating=Avg('reviews__rating')).order_by('-avg_rating')

输出

python
<QuerySet [<Book: Book object (1)>, <Book: Book object (2)>]>

总结

在本文中,我们学习了如何在Django中执行复杂查询,包括过滤、排序、聚合、注解以及使用 Q 对象和 F 表达式。这些功能使得我们能够高效地从数据库中检索数据,而无需编写复杂的SQL语句。

附加资源

练习

  1. 使用 filter() 方法查找所有作者为 "Jane Austen" 的书籍。
  2. 使用 aggregate() 方法计算所有书籍的总页数。
  3. 使用 Q 对象查找所有在2020年之前出版或评分低于3.0的书籍。
  4. 使用 F 表达式更新所有书籍的价格,使其增加10%。

通过完成这些练习,你将更好地掌握Django中的复杂查询技巧。