zoukankan      html  css  js  c++  java
  • 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)

    执行视图函数,得到下图结果

     数据库截图:

    以上就是多表查询的素有内容了,希望和大家多多学习!转载请说明出处,尊重劳动成果!!!

  • 相关阅读:
    webpack基础理解以及使用搭建
    前端优化系列之一:dns预获取 dns-prefetch 提升页面载入速度
    react 什么是虚拟DOM?深入了解虚拟DOM
    react PropTypes 与 DefaultProps
    react todolist代码优化
    react 拆分组件于组件
    react 部分语法补充
    react 的安装和案列Todolist
    浏览器的标准模式和怪异模式
    软件测试基础——慕课网
  • 原文地址:https://www.cnblogs.com/huizaia/p/14481941.html
Copyright © 2011-2022 走看看