Django 多表、跨表、聚合、分组查询

前期准备:

创建表

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    publish_time = models.DateField(auto_now_add=True)  #该字段新增数据会自动添加实时时间

    #出版社 一对多 外键字段建在多的一方
    publish = models.ForeignKey(to='Publish')
    #作者 多对多 外键字段推荐建在查询频率较高的表
    authors = models.ManyToManyField(to='Author')

class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)

class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    #作者详情 一对一  外键字段推荐建在查询频率较高的表
    author_detail = models.OneToOneField(to='AuthorDetail')

class AuthorDetail(models.Model):
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=32)
View Code

Django多表查询

外键字段的增删改查

外键字段在1.X版本中默认就是级联更新级联删除
2.X版本中则需要手动指定(百度)

一对多 publish

增:

# 增 方式1 直接写实际的表字段 publish_id
models.Book.objects.create(title='三国',price='123.12',publish_id=2)
# 增 方式2
publish_obj = models.Publish.objects.get(pk=1)
models.Book.objects.create(title='水浒传',price=66,publish=publish_obj)

改:

# 改 方式1
models.Book.objects.filter(pk=1).update(publish_id=3)
# 改 方式2
publish_obj = models.Publish.objects.get(pk=4)
models.Book.objects.filter(pk=1).update(publish=publish_obj)

多对多

add:

#1.给书籍和作者绑定关系 add

"""
add专门给第三张关系表添加数据
    括号内即可以传数字也可以传对象  并且都支持传多个
"""

book_obj = models.Book.objects.filter(pk=1).first()
# 书籍和作者的关系是由第三张表决定  也就意味着你需要操作第三张表
# 书籍对象点虚拟字段authors就类似于已经跨到书籍和作者的第三张关系表中
# print(book_obj.authors)  #app01.Author.None

# 方式一
book_obj.authors.add(1)  #给书籍绑定一个主键为1的作者
book_obj.authors.add(2,3)

# 方式二
author_obj = models.Author.objects.get(pk=2) 
author_obj1 = models.Author.objects.get(pk=3) 
book_obj.authors.add(author_obj) 
book_obj.authors.add(author_obj,author_obj1)

remove:

# 2.移除书籍与作者的绑定关系 remove

"""
remove专门给第三张关系表移除数据
    括号内即可以传数字也可以传对象  并且都支持传多个
"""

book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.remove(2)
book_obj.authors.remove(1,3)

# author_obj = models.Author.objects.get(pk=2)
# author_obj1 = models.Author.objects.get(pk=3)
# book_obj.authors.remove(author_obj)
# book_obj.authors.remove(author_obj,author_obj1)

set:

# 3 修改书籍与作者的关系   set

"""
set 修改书籍与作者的关系
    括号内支持传数字和对象 但是需要是可迭代对象
"""

book_obj = models.Book.objects.filter(pk=1).first()
# book_obj.authors.set((3,))
book_obj.authors.set((2, 3))

author_obj = models.Author.objects.get(pk=2)
author_obj1 = models.Author.objects.get(pk=3)
book_obj.authors.set((author_obj,))
book_obj.authors.set([author_obj,author_obj1])

clear:

# 4 清空书籍与作者关系

"""
clear()  清空关系
不需要任何的参数
"""

book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.clear()  # 去第三张表中清空书籍为1的所有数据

Django 跨表查询

跨表查询的方式
  1.子查询 将一张表的查询结果当做另外一张表的查询条件
  2.链表查询 

建议:在写sql语句或者orm语句的时候,千万不要想着一次性将语句写完,一定要写一点查一点

 

正反向的概念
  正向
    跨表查询的时候,看外键字段是否在当前数据对象中,如果在的话,查询另外一张关系表 叫正向
    
  反向
    如果不在叫反向

口诀
  正向查询按外键字段
  反向查询按表名小写 看情况加_set

基于对象的跨表查询(子查询)

#正向:

# 1.查询书籍pk为1的出版社名称
book_obj = models.Book.objects.filter(pk=1).first() #先拿到书籍对象
print(book_obj.publish)  #书籍对象点外键字段拿到的是出版社对象
print(book_obj.publish.name)
print(book_obj.publish.addr)

# 2.查询书籍pk为2的所有作者的姓名
book_obj = models.Book.objects.filter(pk=2).first()
# print(book_obj.authors)  # app01.Author.None
print(book_obj.authors.all())  #<QuerySet [<Author: Author object>]>
author_list = book_obj.authors.all()
for author_obj in author_list:
    print(author_obj.name)

# 3.查询作者hank的电话号码
author_obj = models.Author.objects.filter(name='hank').first()
print(author_obj.author_detail)
print(author_obj.author_detail.phone)

"""
    正向查询的时候 当外键字段对应的数据可以有多个的时候需要加.all()
    否则点外键字段即可获取到对应的数据对象
"""

#反向# 4.查询出版社名称为东方出版社出版过的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
print(publish_obj.book_set)  #app01.Book.None
print(publish_obj.book_set.all()) #<QuerySet [<Book: Book object>]>

# 5.查询作者hank写过的书
author_obj = models.Author.objects.filter(name='hank').first()
print(author_obj.book_set) # app01.Book.None
print(author_obj.book_set.all())

# 6.查询手机号为120的作者姓名
author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first()
print(author_detail_obj.author.name)

"""
    基于对象的反向查询 表名小写是否需要加_set.all()?
        一对多和多对多的时候需要加
        一对一不需要  
"""

基于双下划线跨表查询(链表查询)

注意:只要表之间有关系,你就可以通过正向的外键字段或者反向的表名小写,连续跨表操作

# 1.查询书籍pk为1的出版社名称
# 正向
res = models.Book.objects.filter(pk=1).values('publish__name')  # 写外键字段 就意味着你已经在外键字段管理的那张表中
print(res)  #<QuerySet [{'publish__name': '西方出版社'}]>
# 反向
res = models.Publish.objects.filter(book__pk=1).first() # 拿出版过pk为1的书籍对应的出版社
print(res.name)  #西方出版社

# 2.查询书籍pk为1的作者姓名和年龄
# 正向
res = models.Book.objects.filter(pk=1).values('title','authors__name','authors__age')
print(res)
# 反向
# res = models.Author.objects.filter(book__pk=1)  # 拿出出版过书籍pk为1的作者
res = models.Author.objects.filter(book__pk=1).values('name','age')
print(res)

# 3.查询作者是hank的年龄和手机号
# 正向
res = models.Author.objects.filter(name='hank').values('age','author_detail__phone')
print(res)
# 反向
# res = models.AuthorDetail.objects.filter(author__name='hank') #拿到hank的个人详情
res = models.AuthorDetail.objects.filter(author__name='hank').values('phone','author__age')
print(res)

# 4.查询书籍pk为的1的作者的手机号
# 正向
res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
print(res)   #<QuerySet [{'authors__author_detail__phone': 120}]>
# 反向
res = models.AuthorDetail.objects.filter(author__book__pk=1).values('phone')
print(res)  #<QuerySet [{'phone': 120}]>

聚合查询

关键字:aggregate

from django.db.models import Max,Min,Avg,Count,Sum
# 查询所有书的平均价格 res = models.Book.objects.aggregate(Avg('price')) print(res) # 查询价格最贵的书 res = models.Book.objects.aggregate(Max('price')) print(res) #查询书的总数 res = models.Book.objects.aggregate(Count("pk")) print(res) # 查询所有书的总价 res = models.Book.objects.aggregate(Sum('price')) print(res)

分组查询

关键字:annotate

'''
models后面点什么表名,后面如果直接跟annotate,那就是按照表名分组
'''

#
1.统计每一本书的作者个数 res = models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num') print(res) # 2.统计出每个出版社卖的最便宜的书的价格 res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price','book__title') print(res) # 3.统计不止一个作者的图书 res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title') print(res) # 4.查询各个作者出的书的总价格 res = models.Author.objects.annotate(price_sum=Sum('book__price')).values('name','price_sum') print(res) #如何按照表中的某一个指定字段分组 """ res = models.Book.objects.values('price').annotate() 就是以价格分组 """
posted @ 2020-01-08 20:47  Hank·Paul  阅读(564)  评论(0编辑  收藏