Django入门教程

前言

第一章: django快速入门

第二章: django MTV架构

第三章: django视图

第四章: django模板

第五章: django模型

第六章: django后台管理系统

第七章: 项目实战-简易的博客系统

第八章:django表单

第九章:django用户认证系统

第十章:django中的会话

第十一章:django安全

第十二章:django性能优化

第十三章:django实用工具

首页 > Django入门教程 > 第五章: django模型 > 5.8节: QuerySet进阶操作

5.8节: QuerySet进阶操作

薯条老师 2020-08-11 07:55:00 235392 0

编辑 收藏

广州番禺Python, Java小班周末班培训

薯条老师在广州做Python和Java的小班培训,一个班最多10人,学员的平均就业薪资有11K不在广州的同学可以报名线上直播班,跟线下小班的同学们同步学习。培训的课程有Python爬虫,Python后端开发,Python办公自动化,Python大数据分析,Python量化投资,Python机器学习,Java中高级后端开发。授课详情请点击:http://chipscoco.com/?cate=6

5.8.1 字段查询

使用QuerySet中的字段查询可以构造一个复杂的where子句,字段查询可用于QuerySet对象的filter,exclude,get等方法中。QuerySet中的字段查询采用field__lookuptype的查询格式:field表示模型中的字段名,lookuptype表示字段查询的类型。

常用的字段查询类型:

(1) exact

exact表示精确匹配,在exact类型中加上一个i的前缀,表示忽略大小写, 否则表示区分大小写。传递None值时,表示在数据库中查询字段值为NULL的数据。

代码实例:

Blog.objects.filter(id__exact=1)

上述代码表示筛选出id值为1的数据。

Blog.objects.filter(title__iexact='python')

上述代码表示筛选出title值为python(忽略大小写)的数据。

(2) contains

contains表示模糊匹配,同样可以在类型前面加上一个i的前缀,表述忽略大小写。

代码实例

Blog.objects.filter(title__icontains='python')

上述代码表示筛选出title中包含字符串'python'(忽略大小写)的数据。

(3) in

成员匹配,用来查询在一个集合中的数据,通常传递一个可迭代对象,例如列表,元组,字符串。

代码实例:

Blog.objects.filter(category__in=(0,1))

上述代码表示筛选出category值为0或1的数据。也可以将QuerySet对象作为参数传递给in操作符。

代码实例:

inner_qs = Blog.objects.filter(title__icontains='python')
Blog.objects.filter(author__in=inner_qs)

上述代码表示先获取在数据库中title包含python(不区分大小写)的所有数据,然后以此为基准,获取author值为基准数据中的所有数据。例如基准数据中的author值为:'红炉点雪','Backer',则代码Blog.objects.filter(author__in=inner_qs),表示从数据库中筛选出作者为'红炉点雪'或'Backer'的所有数据。

(4) gt,gte,lt,lte

gt,gte,lt,lte分别表示关系运算中的大于,大于等于,小于,小于等于。

代码实例:

Blog.objects.filter(id__gte=1)

上述代码表示从数据库中筛选出id值大于等于1的所有数据。

(5) startswith,endswith

startswith,endswith分别表示以特定的子字符串作为前缀,后缀。

代码实例:

Blog.objects.filter(title__startswith='python')

上述代码表示从数据库中筛选出title值以'python'作为前缀的所有数据。

(6) range

使用range来表示范围匹配。

代码实例:

import datetime
start_date = datetime.date(2019, 1, 1)
end_date = datetime.date(2019, 3, 31)
Blog.objects.filter(pub_date__range=(start_date, end_date))

上述代码表示从数据库中筛选出pub_date在2019年1月1日到2019年3月31日之间的所有数据。

(7) date

使用date来进行日期匹配。

代码实例:

import datetime
Blog.objects.filter(pub_date__date=datetime.date(2019,11,21))

上述代码表示从数据库中筛选出pub_date为2019年11月21日的所有数据。在进行日期匹配中,可与关系运算类型gt,gte,lt,lte等组合成复合查询。

代码实例:

import datetime
Blog.objects.filter(pub_date__date__gte=datetime.date(2019,10,21))

上述代码表示从数据库中筛选出pub_date大于等于2019年11月21日的所有数据。

(8) year,mongth, day

year,mongth, day分别表示进行年份,月份,日份的匹配。

代码实例:

Blog.objects.filter(pub_date__year=2019)

上述代码表示从数据库中筛选出pub_date的年份为2019的所有数据。同样可以与关系运算类型gt,gte,lt,lte等组合成复合查询。

代码实例

Blog.objects.filter(pub_date__year__gte=2018)

上述代码表示从数据库中筛选出pub_date的年份大于等于2018的所有数据。

(9) isnull

isnull表示从数据库中查询值是否为NULL的数据。

代码实例:

Blog.objects.filter(pub_date__isnull=True)

上述代码表示从数据库中筛选出pub_date为NULL的所有数据。

 5.8.2 数据排序

(1) QuerySet.order_by(*fields)

使用order_by方法可以覆盖在Meta类中定义的排序方式。fields表示传递排序的字段名。在字段名前面加-符号表示降序排序,?表示随机排序,不加任何符号表示按升序排序。

代码实例:

Blog.objects.order_by('-id')

上述代码表示在数据库中根据id进行降序排序。

5.8.3 数据去重

(1) QuerySet.distinct(*fields)

可选的参数fields表示根据特定的字段来进行数据去重,Django目前的实现中仅支持 PostgreSQL数据库。当使用其它类型的数据库时,distinct方法不能携带任何参数,需结合values方法来进行数据去重。

代码实例:

Blog.objects.values('author').distinct()

上述代码表示对author字段进行去重。

 代码实例:

Blog.objects.distinct('author')

上述代码同样表示对author字段进行去重,但仅支持PostgreSQL数据库。

5.8.4 Extra查询

QuerySet.extra(select=None,where=None, params=None,tables=None, order_by=None, select_params=None)

 通过QuerySet的extra方法来构造一个复杂的WHERE子句。select参数是一个字典类型,键名为查询语句的结果的别名,键值为对应的查询语句(可以是一个查询子语句)。select_params是一个元组类型,表示SELECT语句的参数。

代码实例:

Blog.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})

在上述代码中查询表达式"pub_date > '2006-01-01'"的结果,并将结果的别名设置为is_recent。使用select_params来传递参数:

Blog.objects.extra(select={'is_recent': "pub_date > '%s'"}, select_params=('2006-01-01',))

上述代码同样是查询表达式"pub_date > '2006-01-01'"的结果,并将结果的别名设置为is_recent。where参数是一个列表,用来构造where子句,列表中存在多个条件时,表示AND关系, params表示传递给where语句的参数。

代码实例:

Blog.objects.extra(where=["author='%s' OR "author='%s'", "title = '%s'"],params=('Backer','Lohan','python'))

order_by参数的用法同QuerySet中的order_by方法。

代码实例:

q = Blog.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
q = q.extra(order_by=['-is_recent'])

5.8.5 聚合查询

(1) QuerySet.aggregate(*args, **kwargs)

使用aggregate来进行聚合查询,例如查询数据列的最大值,最小值,平均值, 进行求和,数量统计等。aggregate返回的结果为一个字典类型,字典键名的默认格式:field__method。field表示字段名,method表示聚合方法。django内置的聚合方法:Max,Min,Avg,Sum,Count,分别表示对数据列计算最大值,最小值,平均值,求和,数量统计。聚合方法需从django.db.models中进行导出。

代码实例:

from django.db.models import Max,Min
 
class Book(models.Model):
    price = models.FloatField()
 
Book.objects.aggregate(Max('price'),Min('price'))
'''
执行aggregate方法返回的结果格式:
{'price__max': 99, 'price__min': 18}
'''

通过在aggregate方法中指定关键字参数,可以覆盖默认的键名格式。代码实例:

from Django.db.models import Max,Min
 
class Book(models.Model):
    price = models.FloatField()
 
# 在aggregate方法中指定关键字参数,可以覆盖默认的键名格式
Book.objects.aggregate(max_price=Max('price'), min_price=Min('price'))

'''
执行aggregate方法返回的结果格式:
{'max_price': 99, 'min_price': 18}
'''

5.8.6 分组查询

(1) QuerySet.annotate(*args, **kwargs)

使用annotate来进行分组查询,参数用法同aggregate,返回的结果为QuerySet对象。annotate方法默认根据主键进行分组,如需按指定的字段进行分组,需结合values方法。为便于进行代码演示,先准备一张数据表programmer (id为主键):

id

name

 

sex

1

小美

2

小丽

3

小草

代码实例:

from django.db.models import Count
 
# 默认按主键id进行分组
Programmer.objects.annotate(Count('sex'))
 
'''
执行annotate方法返回的结果:
<QuerySet [{'id': 1, 'name': '小美','sex': '女','sex__count': 1}, 
{'id': 2, 'name': '小丽','sex': '女','sex__count': 1},
{'id': 3, 'name': '小草','sex': '男','sex__count': 1}]>
'''

在执行annotate方法前,先在values方法中指定字段名,可以按指定的字段进行分组。

代码实例:

from Django.db.models import Count
 
# 默认按主键id进行分组
Programmer.objects.values('sex').annotate(Count('sex'))
 
'''
执行annotate方法返回的结果:
<QuerySet [{'sex': '女','sex__count': 2}, 
{'sex': '男','sex__count': 1}]
>
'''

5.8.7  F查询与Q查询

在django中,可以使用F查询来直接表示模型字段的值。使用F表达式的优势在于,无需将模型字段的值预先从数据库导入到python内存中,django会自动将F表达式转换为SQL语句。定义一个表示程序员的模型:

class Programmer(models.Model):
    name = models.CharField(max_length=10)
    salary = models.IntegerField(default=3000)
    age = models.IntegerField(default=18)
    married = models.BooleanField(default=True)

时光又流逝了一年,现在将程序员的年龄全部加一岁。不使用F表达式的代码实例:

programmers = Programmer.objects.all()
# 批量更新时,得先从数据库中取出模型字段的值
# 访问模型字段时会触发QuerySet的evaluate
 
for programmer in programmers:
    programmer.age = programmer.age+1

使用F表达式的代码实例:

from django.db.models import F
# 直接使用F表达式来表示模型字段的值,无需从数据库中读出数据,提升了查询性能
# django会自动将F表达式转换为数据库中的SQL语句
Programmer.objects.update(age=F('age')+1)

Q查询类似于F查询,两者的区别:Q查询是一个对象,F查询是一个表达式。Q查询在对象内部封装了SQL表达式,使用Q对象时,通过组合& 、|、~等操作符,可以构造复杂的数据库查询(&表示逻辑与,|表示逻辑或,而~表示逻辑非)。使用Q对象查询年纪大于35岁且薪水小于15000, 且未婚的程序员:

from django.db.models import Q
inner_qs=Programmer.objects.filter(Q(salary__lt=15000) & Q(age__gt=35) & ~Q(married=True))

然后全部删除:

inner_qs.delete()

5.8.8 最具实力的小班培训

薯条老师在广州做Python和Java的小班培训,一个班最多10人。不在广州的同学可以报名线上直播班,跟线下小班的同学们同步学习。打算参加小班培训的同学,必须遵守薯条老师的学习安排,认真做作业和项目。把知识学好,学扎实,那么找到一份高薪的工作就是很简单的一件事。

(1) Python后端工程师高薪就业班,月薪11K-18K,免费领取课程大纲
(2) Python爬虫工程师高薪就业班,年薪十五万,包拿Offer
(3) 数据分析高薪就业班,月薪11K-15K, 免费领取课程大纲
(4)
Python大数据挖掘,量化投资就业班,月薪12K-25K,免费领取课程大纲

扫码免费领取Python学习资料:


欢迎 发表评论: