多表查询, 聚集查询和分组查询
有如下模型为例
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
website = models.URLField()
class Author(models.Model):
name = models.CharField(max_length=30)
class AuthorDetail(models.Model):
sex = models.BooleanField(max_length=1, choices=((0,'男'),(1,'女'),))
email = models.EmailField()
birthday = models.DateField()
author = models.OneToOneField(Author, on_delete=models.CASCADE)
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
publication_date = models.DateField()
一. 多表查询
1)查询作者的所有完整信息
注意authordetail表中没有作者名字,名字在author表中
AuthorDetail.objects.values('sex','email','address','author__name')
author是AuthorDetail表中的外键字段,在外键后面加2个下划线跟上Author表中的name属性,就可输出Author表中的名字
如果想单独获得某个作者的姓名,如下
author_detail = AuthorDetail.objects.filter(email="123@qq.com")
name1 = author_detail.author.name
2)查询<<我的祖国>>这本书的作者名字,出版社名字
书和作者是多对多关系
Book.objects.filter(title='我的祖国').values('authors__name')
Book.objects.filter(title='我的祖国').values('publisher__name')
3)查询胡大海写了什么书
Book.objects.filter(authors__name='胡大海').values('title')
4)查询广东人民出版社出了什么书
Book.objects.filter(publisher__name='广东人民出版社').values('title')
5)查询广东人民出版社都有哪些作者出过书
Book.objects.filter(publisher__name='广东人民出版社').values('author__name')
多表查询技巧
1. 两个下划线可生成连接查询,查询关联的字段信息,可用于外键查询主键字段信息,用objects操作
例如:book = Book.objects.filter(publisher__name='广东人民出版社')
2. _set提供了对象访问相关联表数据的方法,使用外键相关模型的小写名称,下划线和单词set。但是这种方法只能是关键类访问外键类
我们有模型Publisher和Book,而Book类中我们通过外键关联到了Publisher。
下面我们定义一个publisher对象表示一个出版社,就可以使用publisher.book_set的方法获取相关联的书籍信息了
publisher = Publisher.objects.get(name='广东人民出版社')
publisher.book_set.all().values()
book.authors_set.all() 这种方法会报错
因为authors不是Book类中的外键,这样操作行不通
注意:
使用
filter
过滤的时候,不仅仅可以指定本模型上的某个属性要满足什么条件,还可以指定相关联的模型满足什么属性比如查找所有书的标题为title1的出版商
pubs = Publisher.objects.filter(book__title = "title1") #注意这里用Book类的小写加__title的方式
二. 常见的查询方法
常见的查询相关的API
1)get(**kwargs):返回于所有筛选条件相匹配的对象,返回结果只有一个。如果符合条件的对象超过一个,就抛出MultipleObjectsReturn异常,如果没找到符合条件的对象,抛出DoesNotExist异常。
注意:
它返回的不是QuerySet对象,而是models的对象,比如pub=Publisher.object.get(id=1)
type(pub)返回结果为class 'hello.models.Publisher'
2)all(): 查询所有结果
3)filter(**kwargs):包含与所筛选条件相匹配的对象,结果可有多个
4)exclude(**kwargs):包含那些与所选条件不匹配的对象,和filter相反
5)order_by(*fields):对查询结果排序
6)reverse():对查询结果反向排序
7)distinct():从返回结果中剔除重复记录
8)values(*fields):返回一个ValuesQuerySet, 一个特殊的QuerySet子类,运行后得到的是一个可迭代的字典序列
9)values_list(*fields): 与values()功能一样,只是返回结果是元组序列
10)count():返回数据库中匹配查询(QuerySet)的对象数量
11)first(): 返回第一条记录,等价于[:1][0]
例如Publisher.objects.all().first()
12) last(): 返回最后一个记录,等价于[::-1][0]
13) exists() :如果QuerySet包含数据,就返回True,否则返回False
例如:Publisher.objects.all().exists()
三. 聚集查询和分组查询
先看QuerySet里的两个函数
1. annotate(*args,**kwargs):可以为QuerySet中的每个对象添加注解。通过计算查询结果中的每个对象所关联的对象集合,得到总值(也可以是平均值等),用于分组查询
2. aggregate(*args, **kwargs): 通过对QuerySet进行计算,返回一个聚合值的字典。aggregate()中的每个参数指定一个包含在字典中的返回值。用于聚合查询
一些聚合函数所在位置:django.db.models,举例如下
1. Avg: 返回所给字段平均值
2. Count:根据所给的关联字段返回被关联model的数量
3. Max: 返回所给字段的最大值
4. Min:返回所给字段的最小值
5. Sum:计算所给字段值总和
实例
1. 在Book模型中增加一个price属性
price = models.DecimalField(max_digits=5, decimal_places=2, default=10)
2. 查询广东人民出版社出了多少本书
Publisher.objects.filter(name='广东人民出版社').count() #注意count是小写, 是QuerySet提供的一个方法
如果使用聚合函数,如下
from django.db.models import *
Publisher.objects.filter(name='广东人民出版社').aggregate(Count('name'))
可以自定义个别名
Publisher.objects.filter(name='广东人民出版社').aggregate(mycount = Count('name'))
3. 查询胡大海出的书的总价格是多少
Book.objects.filter(authors__name = '胡大海').aggregate(Sum('price'))
4. 查询各作者出书的总价格是多少, 需要进行分组
Book.objects.values('authors__name').annotate(Sum('price'))
其中values()可以当做分组条件,annotate()用于分组查询
5. 查询各出版社最便宜的书价
Book.objects.values('publisher__name').annotate(Min('price'))
on_delete=models.CASCADE
努力生活,融于自然