Django之ORM查询进阶

时间:2022-02-02 03:01:17

基于双下划线的双表查询

分组与聚合函数

基于双下划线的双表查询

Django 还提供了一种直观而高效的方式在查询(lookups)中表示关联关系,它能自动确认 SQL JOIN 联系。要做跨关系查询,就使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的 model 为止。

Django之ORM查询进阶Django之ORM查询进阶
# 练习1:  查询人民出版社出版过的所有书籍的名字与价格(一对多)

# 正向查询 按字段:publish

queryResult
=Book.objects
            .filter(publish__name
="人民出版社")
            .values_list(
"title","price")

# 反向查询 按表名:book

queryResult
=Publish.objects
              .filter(name
="人民出版社")
              .values_list(
"book__title","book__price")



# 练习2: 查询egon出过的所有书籍的名字(多对多)

# 正向查询 按字段:authors:
queryResult=Book.objects
            .filter(authors__name
="yuan")
            .values_list(
"title")

# 反向查询 按表名:book
queryResult=Author.objects
              .filter(name
="yuan")
              .values_list(
"book__title","book__price")


# 练习3: 查询人民出版社出版过的所有书籍的名字以及作者的姓名


# 正向查询
queryResult=Book.objects
            .filter(publish__name
="人民出版社")
            .values_list(
"title","authors__name")
# 反向查询
queryResult=Publish.objects
              .filter(name
="人民出版社")
              .values_list(
"book__title","book__authors__age","book__authors__name")


# 练习4: 手机号以151开头的作者出版过的所有书籍名称以及出版社名称

queryResult
=Book.objects
            .filter(authors__authorDetail__telephone__regex
="151")
            .values_list(
"title","publish__name")
代码

 

 
#手机号以456开头的作者出版过的所有书籍的名字以及出版社的名字
#方法1
authorobj=models.AuthorDetail.objects.filter(telph__startswith="456").first()
# print(authorobj.authordetail.book_set.all().values("title","publish__name"))
#方法2
# print(models.Book.objects.filter(authorlist__authordetail__telph__startswith="456").values("title","publish__name"))#都是通过自己里面的字段跳转到别的字段

 

 注意:

反向查询时,如果定义了related_name ,则用related_name替换表名,例如: publish = ForeignKey(Blog, related_name='bookList'):

Django之ORM查询进阶Django之ORM查询进阶
# 练习1:  查询人民出版社出版过的所有书籍的名字与价格(一对多)
 
    
# 反向查询 不再按表名:book,而是related_name:bookList
 
    queryResult
=Publish.objects
              .filter(name
="人民出版社")
              .values_list(
"bookList__title","bookList__price")
代码

注意:    双下划线的跨表查询  不用__set了

#双下划线的跨表查询
# linux这本书的出版社的地址
# ret=models.Book.objects.filter(title="linux").values("publish__addr")
# print(ret)
# ret=models.Publish.objects.filter(book__title="linux").values("addr")
# print(ret)
#查询机械出版社出版过的所有书籍的名字与价格
# ret=models.Publish.objects.filter(name="机械出版社").values("book__title","book__price")
# print(ret)
# models.Book.objects.filter(publish__name="机械出版社").values("title","price")
# print(ret)
#查询frank出过所有书籍的名字
# ret=models.Author.objects.filter(name="frank").values("book__title","book__price")
# print(ret)
# ret1=models.Book.objects.filter(authorlist__name="frank").values("title","price")
# print(ret1)
#手机号以456开头的作者出版过的所有书籍的名字以及出版社的名字
#方法1
authorobj=models.AuthorDetail.objects.filter(telph__startswith="456").first()
# print(authorobj.authordetail.book_set.all().values("title","publish__name"))
#方法2
# print(models.Book.objects.filter(authorlist__authordetail__telph__startswith="456").values("title","publish__name"))#都是通过自己里面的字段跳转到别的字段

#聚合函数
from django.db.models import Avg,Sum,Count,Max,Min
# ret =models.Book.objects.all().aggregate(priceSum=Sum("price"))#结果是字典可以替换名字
# ret = models.Book.objects.all().aggregate(priceAVG=Avg("price"),priceSum=Sum("price"))
# print(ret)
# 分组函数 annote函数
#查询每一本书的作者个数
# ret= models.Book.objects.all().annotate(c=Count("authorlist__name"))
# print(ret)#Queryset对象

#每一个出版社出版过的最便宜的书:
cc=models.Publish.objects.all().annotate(s=Min("book__price"))#如果是跨表查询就用表明__加id
for i in cc:
print(i.s)

 

聚合查询与分组查询

聚合:aggregate(*args, **kwargs)

Django之ORM查询进阶Django之ORM查询进阶
:aggregate(*args, **kwargs)
1
2
3
4
# 计算所有图书的平均价格
    >>> from django.db.models import Avg
    
>>> Book.objects.all().aggregate(Avg('price'))
    {
'price__avg': 34.35}
View Code

aggregate()QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它。

Django之ORM查询进阶Django之ORM查询进阶
>>> Book.objects.aggregate(average_price=Avg('price'))
{
'average_price': 34.35}
View Code

如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:

>>> from django.db.models import Avg, Max, Min
>>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
{
'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}#Decimal数据格式

分组:annotate()

QuerySet中每一个对象都生成一个独立的汇总值。

(1) 练习:统计每一本书的作者个数

Django之ORM查询进阶Django之ORM查询进阶
  #查询每一本书的作者个数
# ret= models.Book.objects.all().annotate(c=Count("authorlist__name"))
# print(ret)#Queryset对象
View Code

(2)每一个出版社出版过的最便宜的书:
Django之ORM查询进阶Django之ORM查询进阶
cc=models.Publish.objects.all().annotate(s=Min("book__price"))#如果是跨表查询就用表明__加id
for i in cc:
print(i.s)
View Code

annotate的返回值是querySet,如果不想遍历对象,可以用上valuelist:

queryResult= Publish.objects
            .annotate(MinPrice
=Min("book__price"))
            .values_list(
"name","MinPrice")
print(queryResult)

方式2:

queryResult=Book.objects.values("publish__name").annotate(MinPrice=Min('price'))

注意:values内的字段即group by的字段

(3) 统计每一本以py开头的书籍的作者个数:

 queryResult=Book.objects
           .filter(title__startswith
="Py")
           .annotate(num_authors
=Count('authors'))

(4) 统计不止一个作者的图书:

queryResult=Book.objects
          .annotate(num_authors
=Count('authors'))
          .filter(num_authors__gt
=1)

(5) 根据一本图书作者数量的多少对查询集 QuerySet进行排序:

Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')

(6) 查询各个作者出的书的总价格:

# 按author表的所有字段 group by
queryResult=Author.objects
              .annotate(SumPrice
=Sum("book__price"))#跳转到另一个表里
              .values_list(
"name","SumPrice")
print(queryResult)

#按authors__name group by
queryResult2=Book.objects.values("authors__name")
              .annotate(SumPrice
=Sum("price"))
              .values_list(
"authors__name","SumPrice")
print(queryResult2)

注意:很多代码没有加models