zoukankan      html  css  js  c++  java
  • Django模型层的多表操作(2)

    一基于双划线的跨表查询

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

    '''
        正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表
    '''

    一对多查询

    # 练习:  查询苹果出版社出版过的所有书籍的名字与价格(一对多)
    
        # 正向查询 按字段:publish
    
        queryResult=Book.objects
                .filter(publish__name="苹果出版社")
                .values_list("title","price")
    
        # 反向查询 按表名:book
    
        queryResult=Publish.objects
                  .filter(name="苹果出版社")
                  .values_list("book__title","book__price")

    多对多查询  

    # 练习: 查询alex出过的所有书籍的名字(多对多)
    
        # 正向查询 按字段:authors:
        queryResult=Book.objects
                .filter(authors__name="yuan")
                .values_list("title")
    
        # 反向查询 按表名:book
        queryResult=Author.objects
                  .filter(name="yuan")
                  .values_list("book__title","book__price")

    一对一查询

        # 查询alex的手机号
        
        # 正向查询
        ret=Author.objects.filter(name="alex").values("authordetail__telephone")
    
        # 反向查询
        ret=AuthorDetail.objects.filter(author__name="alex").values("telephone")

    进阶练习(连续跨表)

    # 练习: 查询人民出版社出版过的所有书籍的名字以及作者的姓名
    
    
        # 正向查询
        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")
    
    
    # 练习: 手机号以151开头的作者出版过的所有书籍名称以及出版社名称

    # 方式1: queryResult=Book.objects             .filter(authors__authorDetail__telephone__regex="151")             .values_list("title","publish__name") # 方式2: ret=Author.objects .filter(authordetail__telephone__startswith="151") .values("book__title","book__publish__name")

    related_name

    反向查询时,如果定义了related_name ,则用related_name替换表名,例如:

    1
    publish = ForeignKey(Blog, related_name='bookList')
    # 练习: 查询人民出版社出版过的所有书籍的名字与价格(一对多)

    # 反向查询 不再按表名:book,而是related_name:bookList

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

    二.聚合查询和分组查询

    1.聚合

        aggregate(*args, **kwargs)

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

    # 计算所有图书的平均价格
        >>> from django.db.models import Avg
        >>> Book.objects.all().aggregate(Avg('price'))
        {'price__avg': 34.35}

    如果希望生成不止一个聚合,你可以向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')}
     # 查询所有书籍的平均价格
     from django.db.models import Avg,Max,Sum,Min,Count
     ret=Book.objects.all().aggregate(priceAvg=Avg("price"))
     print(ret) # {'priceAvg': 142.0}
    # 查询所有书籍的个数
    ret=Book.objects.all().aggregate(c=Count(1))
    print(ret) # {'c': 4}

    2.分组

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

      单表分组查询

    查询每一个部门名称以及对应的员工数
    
    emp:
    
    id  name age   salary    dep
    1   alex  12   2000     销售部
    2   egon  22   3000     人事部
    3   wen   22   5000     人事部
    
    
    sql语句:
    select dep,Count(*) from emp group by dep;
    
    ORM:
    emp.objects.values("dep").annotate(c=Count("id")
    #查询书籍表每一个出版社id以及对应的书籍个数
     key: annotate()前values哪一个字段就按哪一个字段group by
    ret=Book.objects.values("publish_id").annotate(c=Count(1))
    print(ret)
    
    # 查询每一个部门的名称以及对应员工的平均薪水
     ret=Emp.objects.values("dep").annotate(avg_salary=Avg("salary"))
     print(ret) # [{'dep': '教学部', 'avg_salary': 2500.0}, {'dep': '保洁部', 'avg_salary': 3500.0}, {'dep': '保安部', 'avg_salary': 4000.0}]>
    
    # 查询每一个省份的名称以及对应的员工最大年龄
    
    ret=Emp.objects.values("pro").annotate(max_age=Max("age"))
    print(ret) # <QuerySet [{'pro': '山东省', 'max_age': 123}, {'pro': '河南省', 'max_age': 23}, {'pro': '河北省', 'max_age': 56}]>

      跨表的分组查询

    查询每一个部门名称以及对应的员工数
    
    emp:
    
    id  name age   salary   dep_id
    1   alex  12   2000       1
    2   egon  22   3000       2
    3   wen   22   5000       2
    
    dep
    
    id   name 
    1    销售部
    2    人事部
    
    emp-dep:
    
    id  name age   salary   dep_id   id   name 
    1   alex  12   2000       1      1    销售部
    2   egon  22   3000       2      2    人事部
    3   wen   22   5000       2      2    人事部
    
    
    sql语句:
    select dep.name,Count(*) from emp left join dep on emp.dep_id=dep.id group by dep.id
    
    ORM:
    dep.objetcs.values("id").annotate(c=Count("emp")).values("name","c")
    class Emp(models.Model):
        name=models.CharField(max_length=32)
        age=models.IntegerField()
        salary=models.DecimalField(max_digits=8,decimal_places=2)
        dep=models.CharField(max_length=32)
        province=models.CharField(max_length=32)
    创建Emp表

    总结 :跨表分组查询本质就是将关联表join成一张表,再按单表的思路进行分组查询。

    # 查询每一个出版社的名称以及对应的书籍平均价格
    ret=Publish.objects.values("name","email").annotate(avg_price=Avg("book__price"))
    print(ret) # <QuerySet [{'name': '苹果出版社', 'avg_price': 117.0}, {'name': '橙子出版社', 'avg_price': 112.0}, {'name': '西瓜出版社', 'avg_price': 222.0}]>
    
        # 查询每一个作者的名字以及出版的书籍的最高价格
     ret=Author.objects.values("pk","name").annotate(max_price=Max("book__price"))
     print(ret)
    
        # 查询每一个书籍的名称以及对应的作者的个数
    ret=Book.objects.values("title").annotate(c=Count("authors"))
    print(ret) # <QuerySet [{'title': 'python', 'authors__count': 2}, {'title': 'linux', 'authors__count': 1}, {'title': 'go', 'authors__count': 1}, {'title': 'java', 'authors__count': 0}]>

    三.F查询与Q查询

    F查询

    在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?

    Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

    1
    2
    3
    4
    # 查询评论数大于收藏数的书籍
     
       from django.db.models import F
       Book.objects.filter(commnetNum__lt=F('keepNum'))

    Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。

    1
    2
    # 查询评论数大于收藏数2倍的书籍
        Book.objects.filter(commnetNum__lt=F('keepNum')*2)

    修改操作也可以使用F函数,比如将每一本书的价格提高30元:

    1
    Book.objects.all().update(price=F("price")+30) 

    Q查询

    filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用对象

    1
    2
    from django.db.models import Q
    Q(title__startswith='Py')

    Q 对象可以使用& 和| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。

    1
    bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))

    等同于下面的SQL WHERE 子句:

    1
    WHERE name ="yuan" OR name ="egon"

    你可以组合& 和|  操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询:

    1
    bookList=Book.objects.filter(Q(authors__name="yuan") & ~Q(publishDate__year=2017)).values_list("title")

    查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:

    1
    2
    3
    bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017),
                                  title__icontains="python"
                                 )
  • 相关阅读:
    java调优参数记录
    Java性能调优实践
    Java常用Json库性能对比
    微服务架构
    css美化页面
    HTML5⑥
    初始css
    HTML⑤
    反射机制
    简单工厂设计模式
  • 原文地址:https://www.cnblogs.com/chenxi67/p/9856968.html
Copyright © 2011-2022 走看看