Django模型数据查询方法

Posted by FanHao on 2020-07-28

说明

python3.6 Django2.2.10

django通过ORM定义模型类,以下为Person,Book模型代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from django.db import models
class Person(models.Model):
"""Person"""
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
age = models.IntegerField()
birthday = models.DateField(verbose_name="生日")
country = models.CharField(max_length=20)

class Book(models.Model):
"""Book表"""
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=30)
author = models.ForeignKey(Person, verbose_name="作者", on_delete=models.DO_NOTHING, related_name="person_writed")
type = models.CharField(verbose_name="类别", max_length=30, blank=True)
price = models.IntegerField()
published_date = models.DateField(verbose_name="出版日期", auto_now=False, auto_now_add=False)

def __str__(self):
return self.name

基本查询

通过调用以下查询方法将得到一个QuerySet查询集,而QuerySet是有缓存的,尤其当查询得到的数据非常巨大时,此时可使用迭代器queryset.iterator(),迭代器作为python的特性,此处不过多

get函数
1
2
3
4
# 仅且返回一条数据,返回空和多条均报错
book = Book.objects.get(id_exact=1)
# exact可省略
book = Book.objects.get(id=1)
all函数
1
2
# 查询所有。返回QuerySet查询集(可以遍历)
books = Book.objects.all()
filter函数

筛选出满足条件的数据,类似=。返回结果为可遍历的QuerySet查询集,以下列举了查询的条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
__exact 精确等于
__iexact 精确等于,忽略大小写
__contains 包含, like '%aaa%'
__icontains 包含,忽略大小写 ilike '%aaa%'
__gt 大于
__gte 大于等于
__lt 小于
__lte 小于等于
__in 存在于一个list范围内
__startswith 以...开头
__istartswith 以...开头 忽略大小写
__endswith 以...结尾
__iendswith 以...结尾,忽略大小写
__range 在...范围内
__year 日期字段的年份
__month 日期字段的月份
__day 日期字段的日
__regex 小写敏感的正则表达式
__iregex 大小写不敏感的正则表达式。
__isnull=True/False

以下为一些例子;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 精确查询,等于,exact可省略
books = Book.objects.filter(title__exact='神雕侠侣')
# 模糊查询,__contains包含
books = Book.objects.filter(title__contains='侠')
# 以...开头,__startswith
books = Book.objects.filter(title__startswith='神')
# 以...结尾,__endswith
books = Book.objects.filter(title__endswith='侣')
# list范围查询,__in
books = Book.objects.filter(title__in=['神雕侠侣','天龙八部'])
books = Book.objects.filter(id__in=[1,3,4])
# 查询2002年出版
books = Book.objects.filter(published_date__year=2002)
# 查询7月生日的
persion = Person.objects.filter(birthday__month=7)
# 查询出版时间大于等于2010年的书籍
books = Book.objects.filter(published_date__year__gte=2010)
# 查询出版时间小于等于2010
books = Book.objects.filter(published_date__year__lte=2010)
exclude函数

与filter方法相反,筛选出不满足条件的数据集,类似!=。同样的,返回结果是可遍历的QureySet查询集

exclude方法为filter方法的取反

1
2
3
# sql语句为:select * from person where age not between 18 and 24。
person = Person.objects.exclude(age__range=(18,24))
#
order_by函数

对查询结果进行排序。返回可遍历的QuerySet查询集。

1
2
3
4
5
6
# 按照年龄大小,升序
person = Person.objects.order_by("age")
# 按照出版日期升序,排序
books = Book.objects.order_by("published_date")
# 按照出版日期降序,排序
books = Book.objects.order_by("-published_date")

聚合函数

aggregate方法

返回使用聚合函数后的字段和值,主要用于数据的统计。

以下列举部分实例,具体代码查询条件根据业务需求实现。

1
2
3
4
5
6
7
8
9
from django.db.models import Avg,Count,Min,Max,Sum
# 统计所有书籍的平均售价
result = Book.objects.all().aggregate(Avg('price'))
# 统计所有作者中,小于40岁的人数
result = Person.objects.filter(age__lte=40).aggregate(count('id'))
# 统计金庸出版书籍的最高价格
result = Book.objects.filter(author__name='金庸').aggregate(Max('price'))
# 统计购买所有金庸出版的书籍多少钱
result = Book.objects.filter(author__name='金庸').aggregate(Sum('price'))
annotate方法

在原来字段的基础上添加一个使用了聚合函数的字段,并且在使用聚合函数的时候,会使用当前这个模型的主键进行分组(group by)

1
2
3
4
5
# 分组 annotate(),查询每一个作者出版过的书的最高价
# 解析:按照作者的名字分组,就要用到values,显示的是字段的名字,
result = Book.objects.values('authors__name').annotate(Max('price'))
# 统计每个国家的作家人数
result = Person.objects.values('country').annotate(Count('id'))

F表达式和Q表达式

F表达式

F表达式主要用来优化ORM操作数据库,还是以上面Book表为例

1
2
3
4
5
6
7
# 因为成本原因,所有书的价格需要上调5元
# 常规代码,先从数据库中提取所有书到python内存中去,然后使用Python代码在每个价格上+10,再保存到数据库中。
# 此种方式代码冗余,耗时且占用资源。
books = Book.objects.all()
for book in books:
book.price += 5
book.save()

使用F表达式之后,代码如下

1
2
from django.db.models import F
Score.objects.update(grade=F('grade')+5)
Q表达式

Q表达式主要用来实现比较复杂的查询语句

1
2
# 以下语句查询价格大于等于100,并且出版年限大于等于2008的所有书籍
books = Book.objects.filter(price__gte=100, published_date__year__gte=2008)

如果我们需要查询价格大于等于100,或者出版年限大于等于的书籍呢。此时Q表达式能够满足我们的需求

1
2
3
# 或运算,满足两者条件之一即可
from django.db.models import Q
books = Book.objects.filter(Q(price__gte=100) | Q(published_date__year__gte=2008))

以上为或运算,Q表达式还可以进行其它的运算,比如&(与)和~(非)等。

1
2
3
4
5
6
# 组合查询,以神开头并且价格大于60 ,或者id大于5的书籍
books = Book.objects.filter(Q(title__startswith="神") & Q(price__gt=60) | Q(id__gt=5))
# Q表达式与不带Q查询条件组合查询,不带Q的查询条件放在最后
books = Book.objects.filter(Q(price__gt=60) | Q(id__gt=5),title__startswith="神")
# ~ 取反,即价格不大于60
b8 = Book.objects.filter(Q(title__startswith="神") & ~Q(price__gt=60) | Q(id__gt=5))