zoukankan      html  css  js  c++  java
  • python之路_django ORM模型(联表)(二)

    一、基于双下划线跨表查询(join查询)

      在上一篇中,我们简单的介绍了基于对象的跨表查询,本章将继续阐述基于双下划线的跨表查询,所用的表格均为上章中所创建的表格。

    ###############基于双下划线的查询:正向查询,按字段,反向查询,按表名###############

    1、一对多

    实例一(正向,用字段):

    # 查询红楼梦的出版社名称
    #方式1:
    ret=Book.objects.filter(title="红楼梦").values("publish__name")           
    print(ret)                                                          # <QuerySet [{'publish__name': '北京出版社'}]>
    # 方式2:
    res=Publish.objects.filter(book__title="红楼梦").values("name")          
    print(res)                                                          #<QuerySet [{'name': '北京出版社'}]>

    实例二(反向,用表名):

    # 查询沙河出版社出版过的书籍名称
    #方式1:
    ret=Publish.objects.filter(name="沙河出版社").values("book__title")
    print(ret)                                                         #<QuerySet [{'book__title': '金品梅2'}, {'book__title': '金品梅3'}]>
    #方式2:
    res=Book.objects.filter(publish__name="沙河出版社").values("title")
    print(res)                                                         #<QuerySet [{'title': '金品梅2'}, {'title': '金品梅3'}]>

    2、多对多

    实例一(正向,用字段):

    # 查询红楼梦所有作者的名字
    ret=Book.objects.filter(title="红楼梦").values("authors__name")
    print(ret)                                                        #<QuerySet [{'authors__name': 'alex'}, {'authors__name': 'egon'}]>

    实例二(反向,用表名):

    #查询alex出版过的所有书籍
    ret=Author.objects.filter(name="alex").values("book__title")
    print(ret)                                                        #<QuerySet [{'book__title': '金品梅2'}, {'book__title': '红楼梦'}]>

    3、一对一

    实例一(正向,用字段):

    # 查询地址在沙河并且email是123的作者的名字
    ret=AuthorDetail.objects.filter(adrr="沙河",email=123).values("author__name")
    print(ret)                                                        #<QuerySet [{'author__name': 'alex'}]>

    实例二(反向,用表名):

    # 查询alex作者的adrr地址
    ret = Author.objects.filter(name="alex").values("authordetail__adrr")
    print(ret)                                                       #<QuerySet [{'authordetail__adrr': '沙河'}]>

    实例三(综合实例):

    #email以456开头的作者出版过的所有书籍名称以及出版社名称  
    ret=Book.objects.filter(authors__authordetail__email__startswith="456").values("title","publish__name") print(ret)

      总结,在上一章的对象查询中,我们可以总结为所有的查询是基于一个models对象,而本节中双下划线查询均是基于queryset对象进行的!反向查询使用的表名同样必须为小写。

    二、聚合函数(aggregate)

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

    #查询所有书籍的平均价格
    # 实例1:
    ret=Book.objects.all().aggregate(Avg("price"))
    print(ret)                                                         #{'price__avg': 172.66666666666666}
    # 实例2:
    res = Book.objects.all().aggregate(avgPrice=Avg("price"))
    print(res)                                                         #{'avgPrice': 172.66666666666666}

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

    # 查询所有书籍的平均价格、价格最大值、价格最小值
    ret = Book.objects.all().aggregate(Avg("price"),Min("price"),Max("price"))
    print(ret)                         #{'price__avg': 172.66666666666666, 'price__min': Decimal('123.00'), 'price__max': Decimal('230.00')}

      以上实例中需要按照如下方式引入相应的模块方法: from django.db.models import Avg, MaxMin

    三、分组函数(annotate)

      annotate()为调用的QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数)。

      实例1:查询每一个出版社出版过的书籍个数

    ret=Publish.objects.all().annotate(num=Count("book__title"))     #可以理解为每一个出版社对象增加一个num字段,该字段值是通过聚合函数联表求得
    for pub_obj  in ret:
        print(pub_obj.name,pub_obj.num)

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

    ret = Publish.objects.all().annotate(num=Count("book__title")).values_list("name","num")
    print(ret)                                                       #<QuerySet [('人民出版社', 0), ('沙河出版社', 2), ('北京出版社', 1)]>

      实例2:查询每一本书的作者个数

    ret=Book.objects.all().annotate(counts=Count("authors__nid")).values("title","counts")
    print(ret)        #<QuerySet [{'title': '金品梅2', 'counts': 2}, {'title': '金品梅3', 'counts': 2}, {'title': '红楼梦', 'counts': 2}]>

     四、练习题解析

      如下例为1-5分别使用基于对象查询和双下划线查询:

    # 1、查询人民出版社出版过的价格大于100的书籍的作者的email
    # 方法一:
    pub_obj = Publish.objects.get(name="人民出版社")
    book_obj = pub_obj.book_set.filter(price__gt=100)
    for book in book_obj:
    print(book.authors.all())
    for author in book.authors.all():
        print(author.authordetail.email)
    #方法二:
    pub_obj=Publish.objects.get(name="人民出版社")
    ret=pub_obj.book_set.filter(price__gt=100).values("authors__authordetail__email")
    print(ret)
    # 2、查询alex出版过的所有书籍的名称以及书籍的出版社的名称
    #方法1:
    book_obj=Author.objects.get(name="alex").book_set.all()
    for book in book_obj:
    print(book.title,book.publish.name)
    # 方法2:
    ret=Book.objects.filter(authors__name="alex").values("title","publish__name")
    print(ret)
    # 3、查询2011年出版社过的所有书籍的作者名字以及出版社名称
    #方法一:
    book_obj= Book.objects.filter(publishDate__year=2011)
    for book in book_obj:
    print(book.authors.all().values("name"),book.publish.name)
    #方法二:
    ret=Book.objects.filter(publishDate__year=2011).values("authors__name","publish__name")
    print(ret)
    # 4、查询住在沙河并且email以123开头的作者写过的所有书籍名称以及书籍的出版社名称
    #方法一:
    book_obj=AuthorDetail.objects.get(adrr="沙河", email__startswith=123).author.book_set.all()
    for book in book_obj:
    print(book.title,book.publish.name)
    
    #方法二:
    ret=AuthorDetail.objects.filter(adrr="沙河",email__startswith=123).values("author__book__title","author__book__publish__name")
    print(ret)
    # 5、查询年龄大于20岁的作者在哪些出版社出版过书籍
    #方法一:
    author_obj = Author.objects.filter(age__gt=20)
    for author in author_obj:
    # print(author.book_set.all())
    for book in author.book_set.all():
        print(book.publish.name)
    #方法二:
    ret=Author.objects.filter(age__gt=20).values("book__authors__name","book__publish__name")
    print(ret)
    
    # 6、查询每一个出版社的名称以及出版过的书籍个数
    ret=Publish.objects.all().annotate(counts=Count("book__nid")).values("name","counts")
    print(ret)
    # 7、查询每一个作者的名字以及出版过的所有书籍的最高价格
    ret=Author.objects.all().annotate(max_price=Max("book__price")).values("name","max_price")
    print(ret)
    # 8、查询每一本书的名字,对应出版社名称以及作者的个数
    ret=Book.objects.all().annotate(counts=Count("authors__nid")).values("title","publish__name","counts")
    print(ret)

    五、F查询与Q查询

      具体介绍如下:

    1、F查询

    2、Q查询

  • 相关阅读:
    ssm框架搭建
    属性注入
    布隆过滤器
    浅谈动态规划
    双指针技巧汇总
    详解二分查找算法
    java内存模型的实现
    JVM内存结构、Java内存模型和Java对象模型
    浅谈动态规划以及相关的股票问题
    了解重构
  • 原文地址:https://www.cnblogs.com/Ebola-/p/8734141.html
Copyright © 2011-2022 走看看