基于双下划线的跨表查询 (join查询)
因为你的数据库中的查询就是重点 那么你的django提供的orm也是查询语句最重点 ,也提供的查询方法比较的多,下面我们学习下类似于MYSQL的连表(join)查询
Django 还提供了一种直观而高效的方式在查询(lookups)中表示关联关系,它能自动确认 SQL JOIN 联系。要做跨关系查询,就使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的model 为止。
这个查找不论是一对一,一对多,多对多都按照:正向查找按字段(关联字段),反向查询按表名(小写)来查找
并且是基于queryset查询就必须是__而基于对象的查询的是用点 .
反向查找:就好比你要查找的信息在另外一个关联内的表然后你就要通过另外一个关联表然后来调用它的字段就是反向通过表名用字段
正向查找: 就是表示过滤的字段在你的表中 然后你就通过你的表来找到自己的字段来查找
过滤查找后再筛选你要查找的内容用value或者values__list来筛选
比如你要查找book对用的作者的名字
你的book可以直接找到关联作者的字段 authors就是直接可以找到你这个book的书名对应的作者的对象 然后再__调用名字字段就可以了
建立表
models:
from django.db import models # Create your models here. class Book(models.Model): title = models.CharField(max_length = 30) price = models.DecimalField(max_digits = 30,decimal_places= 2,null = True) # 最后的True代表可以为空 pub_date = models.DateTimeField() publish = models.ForeignKey(to = 'Publish',to_field = 'id',on_delete = models.CASCADE) authors = models.ManyToManyField(to = 'Author') comment_count = models.IntegerField(default = 0) up_count = models.IntegerField(default = 0) read_count = models.IntegerField(default = 0) def __str__(self): return self.title class Publish(models.Model): name = models.CharField(max_length = 30) email = models.IntegerField() # ad = models.OneToOne addr = models.CharField(max_length = 30) class Author(models.Model): name = models.CharField(max_length = 30) age = models.IntegerField() ad = models.OneToOneField(to = 'AuthorDetial', to_field = 'id' ,on_delete = models.CASCADE) class AuthorDetial(models.Model): gf = models.CharField(max_length =30) tel = models.CharField(max_length = 30) class Emp(models.Model): name = models.CharField(max_length = 30) age = models.IntegerField() salary = models.DecimalField(max_digits=30,decimal_places=3) dep = models.CharField(max_length=30) province = models.CharField(max_length = 30) class Nice(models.Model): id = models.AutoField(primary_key = True) name = models.CharField(max_length = 30)
插入信息:
def add(request): #一对多的添加方式 # book = Book.objects.create(title = '老王转',price = 9.9, pub_date= '1989-06-17',publish_id = 1) # print(book.title) # publish = Publish.objects.create(name = '大中华出版社',email = 123456, addr = '中南海') # print(publish.name) #添加作者 # author = Author.objects.create(name = '老王',age = 17,ad_id = 1 ) # print(author.name) #添加作者和作者女朋友信息 # authors_detical = AuthorDetial.objects.create(gf = '隔壁小妹妹', tel = 110) # print(authors_detical.gf) # authors_d = AuthorDetial.objects.create(gf = '操场小姐姐',tel = 119) # print(authors_d) # authors_id = AuthorDetial.objects.create(gf = '医院小护士',tel = 120) # print(authors_id.gf) #添加作者 # author = Author.objects.create(name = '柳下惠',age = 18, ad_id = 3) # print(author.name) #添加出版社 # Publish.objects.create(name = '华北出版社',email = 23456,addr = '中华北部') # Publish.objects.create(name = '上海出版社',email = 3456, addr = '天南海北') #添加书籍信息 # Book.objects.create(title = '智商与情商',price = 30.5, pub_date = '2017-03-15',comment_count= 300,up_count= 201,read_count= 102 ,publish_id = 2 ) # Book.objects.create(title='人民心论', price=700, pub_date='2013-08-20', comment_count=120, up_count=85, # read_count=67, publish_id=1) # Book.objects.create(title='愚弄', price=40, pub_date='1997-06-15', comment_count=60, up_count=11, # read_count=400, publish_id=3) #为书籍和作者添加关系 # laowng = Author.objects.filter(name = '老王').first() # lz = Author.objects.get(name = '柳下惠') # book = Book.objects.get(title = '愚弄') # book.authors.add(*[laowng,lz]) # book = Book.objects.filter(title = '人民心论').first() # book.authors.add(laowng) # book = Book.objects.get(title = '智商与情商') # book.authors.add(*[lz,laowng])
连续跨表查询需要用到__下划线 然后用values来分组
连续跨表查找 这个时候就用到了关联的字段 当你正向查找的时候 这个关联的字段就好比是一个中间桥梁 可以直接通过__下划线取查找信息
#查询作者的女朋友以110开头的作者出版过的书籍的信息和出版社的名字 # ret = Author.objects.filter(ad__tel__startswith=110).values('book__title','book__publish__name') #首先你先用正向查询查找到作者的女朋友的信息 因为书籍和作者的关系字段在书籍表内然后再用反向查找查找书籍的信息和出版社的信息 # print(ret) # 查询作者的女朋友以110开头的作者出版过的书籍的信息和出版社的名字(正向查找) #因为用的是book表来查找就是正向查找 先用字段通过作者和女朋友的关系字段ad然后找到自己的tel然后再连接publisj # ret = Book.objects.filter(authors__ad__tel__startswith = 110).values('title','publish__name') # print(ret) #查询医院小护士的男朋友 # ret = Author.objects.filter(ad__gf = '医院小护士').values('name') # print(ret) #查询愚弄这本书的作者的女朋友的手机号 # ret = Book.objects.filter(title = '愚弄').values('authors__ad__tel') #先通过正向查询找到书名然后通过字段找到作者表和作者女朋友关系表进行关联的字段再找女朋友的信息 # print(ret)
当你正向查找的时候先找到自己表内的关联的字段 然后通过__下划线就可以直接调用要查询表中的字段名
而反向查找直接通过被查找表直接__自己的字段就可以了
#查询大中华出版社 出版过的所有的书籍和作者的信息 #反向查找 # ret = Publish.objects.filter(name = '大中华出版社').values('book__title','book__authors__name') # print(ret) #正向查找 # ret = Book.objects.filter(publish__name ='大中华出版社').values('title','authors__name') # print(ret) # #查找女朋友的手机号是以119开头的的作者出版的书籍 # ret = Author.objects.filter(ad__tel__startswith = 119).values('book__title') # print(ret) #正向查找 # ret = Book.objects.filter(authors__ad__tel__startswith= 119).values('title') # print(ret )
反向查找直接被查找表 __查找信息字段就可以了
聚合查询:
聚合查询 需要导入聚合函数:
from django.db.models import Avg,Count,Max,Min
导入这个信息的时候你就可以了
# #统计所有的书籍的平均价格 书籍总数书籍的最高价格 # ret = Book.objects.all().aggregate(avg = Avg('price'),count = Count(1),max_price = Max('price')) # print(ret['avg'],ret) #
分组查询:
annotate()来分组
#分组的单表查询 # ret = Book.objects.all().values('title') # print(ret) #这是算出你的每个部门的平均值 #先按照values后面的内容分组然后再用annotate分组统计计算你的平均值 # ret = Emp.objects.values('dep').annotate(avg = Avg('salary')) # print(ret) #统计每个省的总人数 #先按照省份分组然后用分组统计的函数annotate 再用求和count # ret = Emp.objects.values('province').annotate(count = Count(1)) # print(ret) #分组的多表查询 # Publish.objects.values('id').annotate(ad = Avg('book__price') ) # print('*'*100) # ret = Publish.objects.values("id").annotate(avg=Avg("book__price")) # #查询每一个出版社的名称以及对用的书籍的最高价格 # ret = Publish.objects.values('id').annotate(max_pri = Max('book__price')).values('name','max_pri') # print(ret) #这个是先用出版社的id分组 然后连表操作book和Publish然后再对你join后的表进行提取name和最大价格 #这个是求每个出版社出版的名称和出版书籍的平均价格 # ret = Publish.objects.values('id').annotate(avg = Avg('book__price')).values('name','avg') # print(ret) #查询每个作者的名字和出版的书籍的最高价格 # ret = Author.objects.values('id').annotate(max_line = Max('book__price')).values('name','max_line') # print(ret) #查询每一本书籍的名称以及作者的个数 # ret = Book.objects.values('id').annotate(coun = Count('authors__id')).values('title','coun') #先用书籍的id来分组 然后把两个表join起来 因为是正向查找就用到了字段然后找到连表的同时统计这个作者的个数 然后通过连后的表查找书的名字和作者的总个数 # print(ret) #其实分组的多表查询就是你先要确定哪几个表进行连接 然后对应的sql的操作是什么你要了解 然后你要找到分组的字段 然后进行判读是反向还是正向进行字段的查找 然后再对你连接后的表进行提取你想要的内容 #查询不止一个作者的书籍的名称 # ret = Book.objects.values('id').annotate(coun = Count('authors__id')).filter(coun__gt=1).values('title') #这个就是你的 先按照书籍的id来分组然后书籍表和作者表连接 然后把作者表和书籍表连接起来 然后 统计作者的个数个数大于1的条件,然后找出名字 # print(ret) # --- 查询每一个出版社名称以及对应书籍的平均价格 # ret = Publish.objects.values('id').annotate(av = Avg('book__price')).values('name','av') # print() # F比较就是把两个字段直接比较 而以前用的是把字段的值求出来再比较 from django.db.models import F,Q #这个是查询你的评论数大于你的 阅读数加100的书籍 # ret = Book.objects.filter(comment_count__gt = F('read_count')+100) # print(ret)
Q查询:
#Q 需要用到 这三个判读条件 & | ~ # & 是and的意思 |是或的意思 ~是非的意思 #这个是查找你的价格大于50 或者阅读数不是大于30的 并且出版时间的年份是2017年的 ret = Book.objects.filter(Q(Q(price__gt = 50)|~Q(read_count__gt=30)&Q(pub_date__year = '2017'))) print(ret) return HttpResponse('666')