Django之ORM查询进阶

基于双下划线的双表查询

分组与聚合函数

基于双下划线的双表查询

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

# 练习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'):

# 练习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)

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

>>> 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) 练习:统计每一本书的作者个数

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

(2)每一个出版社出版过的最便宜的书:
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

 
 
原文地址:https://www.cnblogs.com/1a2a/p/7757956.html