django之orm多表查询
之前讲了一下单表查询的用法,今天来讲下多表查询的用法。
Part1:创建表,生成表
# model.py # 作者详情表 class AuthorDetail(models.Model): nid = models.AutoField(primary_key=True) birthday = models.DateField() telephone = models.BigIntegerField() addr = models.CharField(max_length=64) # 作者表 class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() author_detail = models.OneToOneField(to='AuthorDetail', to_field='nid', on_delete=models.CASCADE, null=True) # 作者表和作者详情表一对一 # 出版社表 class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() # 书表 class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32, default='abc') publishDate = models.DateField(default=2020-10-20) price = models.DecimalField(max_digits=5, decimal_places=2, default=2) publish = models.ForeignKey(to='Publish', to_field='nid', on_delete=models.CASCADE, null=True) # 书和出版社表多对一 authors = models.ManyToManyField(to='Author') read_num = models.IntegerField(default=0) comment_num = models.IntegerField(default=0)
models写完以后还是老规矩,执行python manage.py makemigrations 在执行python manage.py migrate ,执行完以后你就会发现数据库中生成了对应的models里面的表了
Part2:造数据
首先给publish表新增数据,同样的新增一个视图函数,在视图函数中添加数据
from django.shortcuts import render from django.http import HttpResponse from showOrmCase.models import * # Create your views here. def show(request): Publish.objects.create(name='上海出版社', city='上海', email='18823@163.com') Publish.objects.create(name='南京出版社', city='南京', email='12312@163.com') return HttpResponse('OK')
执行一下视图函数,查看数据库
Publish表数据造好以后,就可以去造和这个表关联的表数据了,通过models显而易见Book(多)和Publish(一)进行了一对多的关联
一对多和一对一添加数据准则:给关联字段赋值,Book表中的关联字段就是publish_id
# model.py from django.http import HttpResponse from showOrmCase.models import * # Create your views here. def show(request): Book.objects.create(title='人与自然', publishDate='2012-10-14', price=200, publish_id=1) Book.objects.create(title='三国演义', publishDate='2012-08-14', price=150, publish_id=1) Book.objects.create(title='红楼梦', publishDate='2012-10-20', price=350, publish_id=2) return HttpResponse('OK')
执行接口后数据就生成了
按同上道理,在author和authordetail也分别添加上数据
那么问题来了,现在4个表的数据都加好了,还剩一个book_authors这张表,这张表是Book表和Authors多对多关联生成的,这个时候就要用到django自带的接口了
from django.http import HttpResponse from showOrmCase.models import * # Create your views here. def show(request): alex = Author.objects.get(name='alex') leogao = Author.objects.get(name='leogao') # 绑定多对多的接口 book = Book.objects.get(nid='1') book.authors.add(alex, leogao) # 一张表的对象.另一张表.add(另一张表的对象) return HttpResponse('OK')
此时执行视图函数,book_authors就有数据了
还有另一种写法
from django.http import HttpResponse from showOrmCase.models import * # Create your views here. def show(request): alex = Author.objects.get(nid='1') leogao = Author.objects.get(nid='2') # 绑定多对多的接口 book = Book.objects.get(nid='2') book.authors.add(1, 2) # 这边也可以写nid
执行接口查看数据库
比如我们想把刚才绑定的数据分开怎么搞呢,这边django也提供了接口
from django.shortcuts import render from django.http import HttpResponse from showOrmCase.models import * # Create your views here. def show(request): alex = Author.objects.get(nid='1') leogao = Author.objects.get(nid='2') # 解除多对多 book = Book.objects.get(nid='2') book.authors.remove(1, 2)
执行接口,查看数据库刚才的第二本书就没了(ps:将remove改成clear时就把所有的数据都清除了)
新增完数据,接下来就是查询了。
Part3:查询
1.基于对象查询
一对多:
''' 一对多 正向查询:按字段 反向查询:表名小写_set.all() book_obj.publish obj Book(关联属性:publish)-------------------->Publish <-------------------- publish_obj.book_set.all() # querySet '''
from django.http import HttpResponse from showOrmCase.models import * # Create your views here. def analyse(request): # 正向查询:查询三国演义这本书的出版社的名字 name = Book.objects.filter(title='三国演义').first().publish.name print('出版社名字', name) # 反向查询:查询上海出版社出版过的书籍名称 name = Publish.objects.filter(name='上海出版社').first().book_set.all() for i in name: print('书籍名称', i.title) return HttpResponse('OK')
执行视图函数,得到下图结果
多对多:
''' 多对多 正向查询:按字段 反向查询:表名小写_set.all() book_obj.authors Book(关联属性:author)-------------------->Author <-------------------- author_obj.book_set.all() # querySet ''' from django.http import HttpResponse from showOrmCase.models import * # Create your views here. def analyse(request): # 正向查询: 查询三国演义这本书的所有作者的名字 author_name = Book.objects.filter(title='三国演义').first().authors.all().values('name') for i in author_name: print('作者名字', i['name']) # 反向查询: 查询alex出版过的所有书籍名称 book_name = Author.objects.filter(name='alex').first().book_set.all().values('title') for key in book_name: print('书籍名称', key['title']) return HttpResponse('OK')
执行视图函数,得到下图结果
一对一:
''' 一对一 正向查询:按字段 反向查询:表名小写 author.obj.authordetail Author(关联属性:authordetail)-------------------->Authordetail <-------------------- authordetail_obj.author # obj ''' from django.http import HttpResponse from showOrmCase.models import * # Create your views here. def analyse(request): # 正向查询: 查询alex的手机号 phone = Author.objects.filter(name='alex').first().author_detail.telephone print('手机号', phone) # 反向查询:查询手机号为22222的作者的姓名和年龄 author_name = AuthorDetail.objects.filter(telephone='22222').first().author print('名字', author_name.name) print('年龄', author_name.age) return HttpResponse('OK')
执行视图函数,得到下图结果
2.基于双下划线跨表查询(join)
准则:正向查询按字段,反向查询按表名小写来告诉ORM引擎join哪张表
一对多:
# 正向查询:查询红楼梦这本书的出版社的名字 publish_name = Book.objects.filter(title='红楼梦').values('publish__name') print('正向查询名字:', publish_name) # 反向查询 publish_name_two = Publish.objects.filter(book__title='红楼梦').values('name') print('反向查询名字:', publish_name_two)
执行视图函数,得到下图结果
多对多:
name = Book.objects.filter(title='三国演义').values('authors__name') print(name) # 反向 name_two = Author.objects.filter(book__title='三国演义').values('name') print(name_two)
执行视图函数,得到下图结果
一对一:
# 对一正向查询: 查询alex的手机号 phone = Author.objects.filter(name='alex').values('author_detail__telephone') print(phone) phone_two = AuthorDetail.objects.filter(author__name='alex').values('telephone') print(phone_two)
执行视图函数,得到下图结果
Part4:聚合和分组查询
聚合查询:
value = Book.objects.all().aggregate(avg_price=Avg("price"), max_price=Max("price")) print(value)
执行视图函数,得到下图结果
聚合查询比较简单,关键词是aggregate,注意点是返回的是一个字典,不是queryset
分组查询:
单表分组查询orm公式:单表模型.objects.values('group by的字段').annotate(聚合函数('统计字段'))
示例一
# 示例1 # 查询每一个部门的名称以及员工的平均薪水 # select avg(salary), name from emp group by dep ret = Emp.objects.values('dep').annotate(avg_salary=Avg('salary')) print(ret)
执行视图函数,得到下图结果
示例二
# 示例2: # 查询每一个省份的名称以及员工数 # select count(id) from emp group by province ret = Emp.objects.values('province').annotate(count_id=Count('id')) print(ret)
执行视图函数,得到下图结果
经过以上两个示例,加上套模型,是不是就很清晰了
多表查询
多表分组查询orm公式:每一个后的表的模型.objects.values('主键').annotate(聚合函数(关联表__统计字段)).values('表模型的所有字段以及统计出来的字段')
示例一
# 查询每一个出版社的名称以及出版的书籍的个数 # 方法一 ret_one = Publish.objects.values('name').annotate(Count('book__title')) # 多表查询还是遵循正向关联字段,反向表明小写 # 方法二 ret = Publish.objects.values('nid').annotate(c=Count('book__title')).values('name', 'c')
print(ret_one) print(ret)
执行视图函数,得到下图结果
显而易见,这两种得出来的结果是一样的,一个是按name进行分组,另一个是按id进行分组,然后再展示name
示例二
# 查询每一个作者的名字以及出版过的书籍的最高价格 ret_one = Author.objects.values('name').annotate(Max('book__price')) ret_two = Author.objects.values('nid').annotate(max=Max('book__price')).values('name', 'max') print(ret_one) print(ret_two)
执行视图函数,得到下图结果
Part5:F,Q查询
F: 当等于后面为一个变量时使用F获取变量的值
示例一
from django.db.models import F, Q # 查询comment_num>read_num ret = Book.objects.filter(comment_num__gt=F('read_num')) print(ret)
执行视图函数,得到下图结果
示例二
Book.objects.all().update(price=F('price')+10) # 给每本书加10块钱
Q: Q 对象可以使用& 和| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象 Q查询,| & ~(反)
示例一
ret = Book.objects.filter(Q(price=210)&Q(comment_num=300)) print(ret)
执行视图函数,得到下图结果
数据库截图:
示例二
ret = Book.objects.filter(~Q(price=510)&Q(comment_num=100)) print(ret)
执行视图函数,得到下图结果
数据库截图:
以上就是多表查询的素有内容了,希望和大家多多学习!转载请说明出处,尊重劳动成果!!!