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)

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

 数据库截图:

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

原文地址:https://www.cnblogs.com/huizaia/p/14481941.html