ORM之查询

Posted yq055783

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ORM之查询相关的知识,希望对你有一定的参考价值。

一 基于对象的跨表查询

 基于对象查询的通式就是:先查找到已知条件,然后使用关联方法去查(正、反不同)。

1)正向查询和反向查询

由关联表去查被关联表,叫正向查询。反之,为反向查询。

分正向、反向查询的原因:

正、反查询方法不同。正向查询通过关联属性去查,而反向查询通过关联表的表名小写去查。(反正都和关联表有关)

2)一对一

首先明晰四张表和多对多关系生成表的关系和字段

技术图片

  A.正向查询          关联属性名

#查询张三的地址

首先找到张三(张三在Book

技术图片

  :.first()是拿到第一条记录。是model对象

其次,判断关联方法

Author表查AuthorDetail表是正向查询,用关联属性名:

技术图片

 Author_obj.authorDetail就关联到AuthorDetail表了,再通过点的方式查到里面具体的字段值

B.反向查询        关联表类名小写

#通过地址苏州查出是谁住那

首先:找到苏州的那个记录(在AuthorDetil表中)

技术图片

  其次:判断关联方法

这是反向查询。用关联表类名的小写去关联到关联表

技术图片

 author_detail_obj.author就关联到关联表了,再通过点的方式调用其中的name.

3)一对多

一对多和一对一方法一样。只是在反向查询时(一对多固定的外键(关联属性)在多的一方,意味着从多到一是正向,从一到多为反向),查询的结果是个集合,此时关联方法为关联类名的小写_set方式,不同于一对一反向查询直接关联类名的小写。

A正向查询           关联属性名

#查询三国演义这本书的出版社是那个       

技术图片

  B反向查询         关联表类名小写_set

# 查询人民出版社出版哪些书

技术图片

  .all()就查出该集合所有的记录。

4)多对多

多对多和一对多查询方式一样

A正向查询         关联属性名

 #三国演义这本书谁写的      Book---------Author

技术图片

  B反向查询           关联表类名小写_set

 # 张三写了哪些书

技术图片

 二 基于双下划线的跨表查询

 基于双下划线的查询就一句话:正向查询按字段反向查询按表名小写用来告诉ORM引擎join哪张表,一对一、一对多、多对多都是一个写法

注:基于上下划线的正、反向查询是基于具体查询时通过哪张表查询。因此一个查找会有正反两个方法。而基于对象查询的是在读题是就确定唯一一个查询(是正向还是反向?)

1)一对一

查询张三的地址:(Author   AuthorDetail)

Models.Author.objects.filter(name=”张三”).values(“authorDetail__addr”)    正向

Modesl.AuthorDetail.objects.filter(author__name=”张三”).values(“addr”)    反向

查询在苏州的作者名字

Models.Author.objects.filter(authorDetail__addr=”苏州”).valuse(“name”)    正向

Models.AuthorDetail.objects.filter(addr=”苏州”).values(“author__name”)     反向

总结:

A.首先确定是用正向还是反向方法,决定models.类名.objects. 的类名是什么。

B题目中有:由a查出bafilter()里,b.values()里。根据前面的类名找出ab哪个在类里,直接写。(注:filter()里是关键字的形式。values()里是字符串的形式)

C.剩下一个根据正向反向原则去写:正向写关联属性名,反向写关联类名小写。加双下划线__

 2)一对多

查询三国演义这本书的出版社是那个    Book    Publish

Models.Book.objects.filter( title=”三国演义”).values(“publishs__name”)        正向

Models.Publish.objects.filter(book__title=”三国演义”).values(“name”)         反向

查询人民出版社出版哪些书          Book    Publish

Models.Book.objects.filter(pubishs__name=”人民出版社”).values(“title”)     正向

Models.Publish.objects.filter(name=”人民出版社”).values(“book__title”)  反向

3)多对多

三国演义是谁写的   Book   Author

Models.Book.objects.filter(title=”三国演义”).values(“authors__name”) 正向

Models.Author.objects.filter(book__title=”三国演义”).values(“”name) 反向

张三写了哪些书

Models.Book.objects.filter(authors__name=”张三”).values(“title”)

Models.Author.objects.filter(name=”张三”).values(“book__titele”)

4)进阶查询------多张表

人民出版社出版的书及作者的名称        Book  Author  Publish

Models.Book.objects.filter(publishs__name=”人民出版社”).values(“title”,”authors__name”)

Models.Author.objects.filter(book__publishs__name=”人民出版社”).values(“book__title”,”name”)

Models.Publish.objects.filter(name=”人民出版社”).values(“book__title”,”book__authors__name”)

手机号以5开头的作者出版过的所有书籍名称以及出版社名称 

四张表 AuthorDetail,Author,Publish,Book

方式一:

Models.AuthorDetial.filter(telephone__startswith(“5”)).values(“author__book__title”,”author__book__publishs__name”)

方式二:

Models.Author.objects.filter(authorDetail__telephone__startswith(“5”)).values(“book__title”,”book__publishs__name”)

方式三:

Models.Publish.objects.filter(book__authors__authorDetail__telephone__startswith(“5”)).values(“book__title”,”name”)

方式四:

Models.Book.objects.filter(authors__authorDetail__telephone__startswith(“5”)).values(“title”,”publishs__name”)

关键点:

技术图片

弄清正向反向关系(正向用关联属性名,反向用关联表类名小写)

以控制器的表为基础,去找。Filter里是已知条件,values里是未知条件。

三 分组查询

1.分组

1)单表分组查询

查询每个出版社的名称以及所在的出版书的本数

A.sql语句

Select title,count(*) from Book group by publishs_id

B.ORM语句

ret=models.Book.objects.values(‘publishs_id’).annotate(a=Count(‘id’)).values(‘title’,’a’)

注:values为分组依据。不写默认依据为id。Annotate里面是聚合函数,而其要有别名。Annotate是对分组统计的结果,即要统计的内容。values进行取值

2)多表查询

统计每个出版社出版的书籍的平均价格(Book,)

方式一

ret = models.Book.objects.values(publishs).annotate(a=Avg(price)).values(‘a’)

分组依据是出版社。从Book表开始找,publishs是关系属性,可作为分组依据(publish_id也可)。聚合函数里直接统计price

方式二:

ret=models.Publish.objects.annotate(a=Avg(book__price)).values(‘a’)

这个方式更直观。分组依据是出版社,直接从Publish表开始找。不写values(分组依据),默认通过Publish的id去找。统计内容书的平均价格,不在Publish表,在Book表中,因此要通过双下划线进行联表操作。反向查询用关联表名小写,所以为book__price

 注意:values()里可以写多个分组依据。当values里所有字段共同相同时才算一组。

总结:跨表分组查询本质就是将关联表join成一张表。可以通过双下划线的方式跨表查询。

 2.F查询和Q查询

1)F查询

F查询针对单表的操作(自己表的两个字段进行比较、字段进行运算)

查询书的点赞数大于评论数的书

from django.db.models import F
Ret=models.Book.objects.filter(goot__gt=F(‘comment’)))

让书籍表中所有书的价格都加上10

models.Book.objects.all().update(price=F(price)+10)

(2)Q查询

Filter里的关键字查询都是按照AND(,)查询的,Q查询提供更多的查询方法。或|、与&、非(~)

查询评论数和点赞数都大于80的书籍

ret=models.Book.objects.filter(Q(good__gt=80)|Q(comment__gt=80))

Q查询有优先级。&>|

ret=models.Book.objects.filter(Q(good__gt=80)|Q(comment__gt=80)&Q(price__gt=100))

先算后面的&,再算前面的|

ret=models.Book.objects.filter(Q(good__gt=80)|Q(comment__gt=80)&Q(price__gt=100),title=“三国演义”)

前面的Q查询作为一个整体,再和,后面的一起查询。

 3.练习题

#1.查询每个作者的名称和他们的书的最高价格     #没有已知条件。就用分组(Author表的id作为分组条件。)

ret=models.Author.objects.annotate(a=Max(book__price)).values(name,a)
print(ret)

 #2.查询作者id大于2的作者姓名和他出版书的平均价格

ret=models.Author.objects.filter(id__gt=2).annotate(a=Avg(book__price)).values(name,a)
 print(ret)

 #3.查询作者id大于1的作者或者年龄大于15的作者的名称以及出版的书的最高价格

ret=models.Author.objects.filter(Q(id__gt=1)|Q(age__gt=15)).annotate(a=Max(book__price)).values(name,a)
print(ret)

 # 4查询每个作者出版的书的最高价格的平均值   #两次统计  先分组  再聚合(把前面的结果做个统计结果)

 ret=models.Author.objects.annotate(a=Max("book__price")).values(a).aggregate(Avg(a))
 print(ret)

 

以上是关于ORM之查询的主要内容,如果未能解决你的问题,请参考以下文章

ORM多表操作之一对多查询之下划线查询

Python学习---ORM查询之基于对象的正向/反向查询

ORM之查询

[Django框架之ORM操作:多表查询,聚合查询分组查询F查询Q查询choices参数]

python测试开发django-76.ORM查询之Q查询

Django之orm查询