多表操作:增删改,基于对象/双下划线的跨表查询、聚合查询、分组查询、F查询与Q查询

目录

一、创建多表模型

一对一:OneToOneField

一对多:ForeignKey

多对多:ManyToManyField

  • 创建表时,会自动添加一个nid字段,并且自增,所以id可以不用手动创建

  • OneToOneField和ForeignKey会自动在后面加上" _id "

  • ManyToManyField会自动创建第三张表

  • 创建表的类,OneToOneField、ForeignKey和ManyToManyField中的to后的主表,

    1、如果用双引号包裹,那么创建主表的类在上在下都可以

    2、如果不用双引号包裹,那么创建主表的类就必须在从表的上方

二、一对多增删改表记录

class Publish(models.Model):
# id如果不写,会自动生成,名字叫nid,并且自增
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
addr = models.CharField(max_length=64)
email = models.EmailField() class Author(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
# 数字类型
sex = models.IntegerField()
# to='AuthorDetail' 加引号,这个表能找到就可以,不用引号,类必须在上面定义
authordetail = models.OneToOneField(to='AuthorDetail', to_field='id') def __str__(self):
return self.name class AuthorDetail(models.Model):
id = models.AutoField(primary_key=True)
phone = models.CharField(max_length=32)
addr = models.CharField(max_length=64) class Book(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2)
publish = models.ForeignKey(to=Publish, to_field='id') authors = models.ManyToManyField(to=Author) def __str__(self):
return self.name

1、一对多添加记录

(1)通过 _id 来添加记录

models.Book.objects.create(name='红楼梦',price=20.0,publish_id=1)

(2)通过对象添加记录

# pk 表示主键,一旦主键改变,还是会找到对应的主键来获取对象
publish = models.Publish.objects.filter(pk=1).first()
models.Book.objects.create(name='红楼梦',price=34.5,publish=publish)

2、一对多删除记录

删除记录同单表删除记录一样

models.Book.objects.filter(name='红楼梦').first().delete()

3、一对多修改记录

(1)通过queryset对象的update方法修改

# 方式一:通过 _id 修改
models.Book.objects.filter(pk=1).update(name='西游记',publish_id=1) # 方式二:通过对象修改
publish = models.Publish.objects.filter(pk=1).first()
models.Book.objects.filter(pk=1).update(name='西游记',publish=publish)

(2)通过对象的属性修改,调用对象的save()方法保存

# 方式一:通过 _id 修改
book = models.Book.objects.filter(pk=1).first()
book.publish_id = 2
book.save() # 方式二:通过对象修改
publish = models.Publish.objects.filter(pk=2).first()
book.publish = publish
book.save()

三、一对一增删改记录

一对一的增删改记录和一对多的方法相同,参考一对多的增删改记录

四、多对多增删改记录

1、多对多增加记录

add()    # 可以传对象,可以传id,可以传多个

(1)通过对象添加记录

# 为红楼梦这本书添加一个作者
tom = models.Author.objects.filter(name='tom').first()
book = models.Book.objects.filter(name='红楼梦').first()
tony = models.Author.objects.filter(name='tony').first()
jack = models.Author.objects.filter(name='jack').first()
book.authors.add(tom)
# 一次添加两个作者,中间用逗号隔开
book.authors.add(tony,jack)

(2)通过 id 添加记录

book = models.Book.objects.filter(name='红楼梦').first()
book.authors.add(1)
# 一次添加两个作者,中间用逗号隔开
book.authors.add(1,2)

2、多对多删除记录

remove()    # 可以传对象,可以传id,可以传多个

(1)通过对象删除记录

# 删除红楼梦作者名字是tom的作者
tom = models.Author.objects.filter(name='tom').first()
book = models.Book.objects.filter(name='红楼梦').first()
book.authors.remove(tom)

(2)通过id删除记录

# 删除红楼梦作者id是1、2的两个作者
book = models.Book.objects.filter(name='红楼梦').first()
book.authors.remove(1,2)

3、多对多清空记录

clear()    # 没有参数
# 清除红楼梦的所有作者
book = models.Book.objects.filter(name='红楼梦').first()
book.authors.clear()

4、多对多修改记录

set()    # 先清空在增加,必须传列表,列表里面可以是对象,可以是id

(1)通过对象修改记录

# 修改红楼梦作者名字为tom
tom = models.Author.objects.filter(name='tom').first()
book = models.Book.objects.filter(name='红楼梦').first()
book.authors.set([tom,])

(2)通过id修改记录

# 修改红楼梦作者为作者id是1、2的作者
book = models.Book.objects.filter(name='红楼梦').first()
book.authors.set([1,2])

五、基于对象的跨表查询--多次查询、子查询

正向查询和反向查询

正向查询:关联字段在从表,由从表查询主表中的数据    -----> 按字段查询
反向查询:关联字段在从表,由主表查询从表中的数据 -----> 按表名小写查询

1、一对一基于对象的跨表查询

正向:正向查询按 字段
反向:反向查询按 表名小写
# 1.查询tom作者的手机号   正向查询
author=Author.objects.filter(name='tom').first()
# author.authordetail 就是作者详情的对象
authordetail=author.authordetail
print(authordetail.phone) # 2. 查询地址是山东的作者名字 反向查询
authordetail=AuthorDetail.objects.filter(addr='山东').first()
# authordetail.author 这是作者对象
author=authordetail.author
print(author.name)

2、一对多基于对象的跨表查询

正向:正向查询按 字段
反向:反向按 表名小写_set.all()
# 1.正向 查询红楼梦这本书的出版社邮箱
book=Book.objects.filter(name='红楼梦').first()
# book.publish 就是出版社对象
pulish=book.publish
print(pulish.email) # 2.反向 查询地址是北京的出版社出版的图书
publish=Publish.objects.filter(addr='北京').first()
# publish.book_set.all() 拿出所有的图书
books=publish.book_set.all()
# 统计一下条数
books=publish.book_set.all().count()
print(books)

3、多对多基于对象的跨表查询

正向:正向查询按 字段.all()
反向:反向按 表名小写_set.all()
# 1.查询红楼梦这本书所有的作者
book=Book.objects.filter(name='红楼梦').first()
book.authors.all() # 是所有的作者,是一个queryset对象,可以继续点
print(book.authors.all()) # 2.查询lqz写的所有书
lqz=Author.objects.filter(name='lqz').first()
books=lqz.book_set.all()
print(books)

六、基于双下划线的跨表查询

1、一对一的基于双下划线的跨表查询

正向:按 字段,跨表可以在filter,也可以在values中
反向:按 表名小写,跨表可以在filter,也可以在values中
# 1.查询tom作者的手机号   正向查询  跨表的话,按字段
# 以author表作为基表
ret=Author.objects.filter(name='tom').values('authordetail__phone')
print(ret) # 2.以authordetail作为基表 反向查询,按表名小写 跨表的话,用表名小写
ret=AuthorDetail.objects.filter(author__name='tom').values('phone')
print(ret)

2、一对多的基于双下划线的跨表查询

正向:按 字段,跨表可以在filter,也可以在values中
反向:按 表名小写,跨表可以在filter,也可以在values中
# 查询出版社为北京出版社出版的所有图书的名字,价格
# 1.以Publish为基表
ret=Publish.objects.filter(name='北京出版社').values('book__name','book__price')
print(ret) # 2.以Book为基表
ret=Book.objects.filter(publish__name='北京出版社').values('name','price')
print(ret)

3、多对多的基于双下划线的跨表查询

正向:按 字段,跨表可以在filter,也可以在values中
反向:按 表名小写,跨表可以在filter,也可以在values中
# 查询红楼梦的所有作者名字
# 1.以Book为基表
ret=Book.objects.filter(name='红楼梦').values('authors__name')
print(ret) # 2.以Author为基表
ret = Author.objects.filter(book__name='红楼梦').values('name')
print(ret)

4、连续跨表查询

一直用双下划线 __ 获取字段

# 查询红楼梦这本书所有的作者的手机号
book=Book.objects.filter(name='红楼梦').first()
authors=book.authors.all()
for author in authors:
authordetail=author.authordetail
print(authordetail.phone) # 方法二,使用连续跨表
ret = Book.objects.filter(name='红楼梦').values('authors__authordetails__phone')
print(ret)

七、聚合查询

1、什么聚合

用聚合函数来汇总多条信息

2、语法

from django.db.models import Avg,Sum,Count,Max,Min
aggregate(*args, **kwargs)

3、聚合函数使用

# 聚合函数
Max('price'),Min('price'),Avg('price'),Sum('price')
# 计算所有图书的平均价格
ret = models.Book.objects.all().aggregate(Avg('price'))
print(ret) # 计算图书的最高价格,最低价格,平均价格,总价
ret = models.Book.objects.all().aggregate(Max('price'),Min('price'),Avg('price'),Sum('price'))
print(ret)

八、分组查询

1、关键注意点

values在前,表示group by,在后,表示取值
filter在前,表示过滤(where),在后,表示having(对分组之后的结果再进行过滤)

2、分组查询案例

# 查询所有作者写的书的总价格大于26的
# filter()在annotate后面,表示对分组后的结果进行筛选,相当于having
# annotate前的values()表示按该字段分组,相当于group by,可以省略,默认会按Author的id分组
# 后面的values()表示取值
ret=Author.objects.all().values('pk').annotate(s=Sum('book__price')).filter(s__gt=26).values('name','s') 等价于 ret=Author.objects.all().annotate(s=Sum('book__price')).filter(s__gt=26).values('name','s')
# 查询各个作者出的书的总价格
# s相当于给求和结果取名字,在vlaues取值中,可以引用
ret = Author.objects.all().annotate(s=Sum('price')).values('name','s')
print(ret)
# 统计不止一个作者的图书
ret=Book.objects.all().values('pk').annotate(c=Count('authors')).filter(c__gt=1).values('name','c')
print(ret) 等价于 ret = Book.objects.annotate(author_num=Count("authors")).filter(author_num__gt=1).values('name','author_num')
print(ret)

九、F查询和Q查询

1、F查询

(1)什么是F查询

如果要对两个字段的值作比较,就不能直接比较,必须要借助F() 的实例,它可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

(2)语法

from django.db.models import F
fliter(commit_num__gt=F('read_num'))

(3)F查询的使用

# 查询评论数大于阅读数的书
book = models.Book.objects.filter(commit_num__gt=F('read_num')).values('name') # 把所有书的评论数加1
models.Book.objects.all().update(commit_num=F('commit_num')+1)

2、Q查询

(1)什么是Q查询

对两个字段的值进行 且、或、非 运算,不能直接运算,需要用Q()的实例

(2)语法

# 且  ----->  &
# 或 -----> |
# 非 -----> ~
from django.db.models import Q
fliter(Q(name='tom')|Q(name='tony'))

(3)Q查询的使用

# 查询不是tom写的书的名字
ret = models.Book.objects.filter(~Q(authors__name='tom')).values('name') # 查询作者名字是tom或者名字是tony的书
ret = models.Book.objects.filter(Q(authors__name='tom')|Q(authors__name='tony')).values('name')

Django框架(十)—— 多表操作:一对一、一对多、多对多的增删改,基于对象/双下划线的跨表查询、聚合查询、分组查询、F查询与Q查询的更多相关文章

  1. Django框架(九)-- 多表操作:一对一、一对多、多对多的增删改,基于对象/双下划线的跨表查询、聚合查询、分组查询、F查询与Q查询

    一.创建多表模型 一对一:OneToOneField 一对多:ForeignKey 多对多:ManyToManyField 创建表时,会自动添加一个nid字段,并且自增,所以id可以不用手动创建 On ...

  2. {django模型层(二)多表操作}一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询、分组查询、F查询和Q查询

    Django基础五之django模型层(二)多表操作 本节目录 一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询.分组查询.F查询和Q查询 六 xxx 七 ...

  3. Django学习——Django测试环境搭建、单表查询关键字、神奇的双下划线查询(范围查询)、图书管理系统表设计、外键字段操作、跨表查询理论、基于对象的跨表查询、基于双下划线的跨表查询

    Django测试环境搭建 ps: 1.pycharm连接数据库都需要提前下载对应的驱动 2.自带的sqlite3对日期格式数据不敏感 如果后续业务需要使用日期辅助筛选数据那么不推荐使用sqlite3 ...

  4. (20)模型层 -ORM之msql 基于双下划线的跨表查询(一对一,一对多,多对多)

    基于对象的跨表查询是子查询 基于双下划线的查询是连表查询 PS:基于双下划线的跨表查询 正向按字段,反向按表名小写 一对一 需求:查询lqz这个人的地址# 正向查询ret = models.Autho ...

  5. Django学习——图书相关表关系建立、基于双下划线的跨表查询、聚合查询、分组查询、F查询、Q查询、admin的使用、使用脚本调用Django、Django查看源生sql

    0 图书相关表关系建立 1.5个表 2.书籍表,作者表,作者详情表(垂直分表),出版社表,书籍和作者表(多对多关系) 一对一 多对多 本质都是一对多 外键关系 3.一对一的关系,关联字段可以写在任意一 ...

  6. Django基础(5) ----基于双下划线的跨表查询,聚合查询,分组查询,F查询,Q查询

    一.基于双下划线的跨表查询 Django 还提供了一种直观而高效的方式在查询(lookups)中表示关联关系,它能自动确认 SQL JOIN 联系.要做跨关系查询,就使用两个下划线来链接模型(mode ...

  7. django基础之day04,必知必会13条,双下划线查询,字段增删改查,对象的跨表查询,双下划线的跨表查询

    from django.test import TestCase # Create your tests here. import os import sys if __name__ == " ...

  8. Django Mysql数据库-基于双下划线的跨表查询

    一.基于双下划线的跨表查询 Django 还提供了一种直观而高效的方式在查询(lookups)中表示关联关系,它能自动确认 SQL JOIN 联系.要做跨关系查询,就使用两个下划线来链接模型(mode ...

  9. django orm 基于双下划线的跨表查询

    一..基于双下划线的跨表查询(join实现) key:正向查询按字段,反向查询按表明小写 1.一对多跨表查询 查询在跨表中可以有两种方式,正向查询就是关键字段在你要搜索的表,没有关键字段就是反向查询 ...

随机推荐

  1. spring相关注解

    spring相关注解: 使用之前需要<context:annotation-config/>在配置文件中启用 @Required 应用于类属性的set方法,并且要求该属性必须在xml容器里 ...

  2. CCflow与基础框架组织机构整合

    SELECT No,Name,Pass,FK_Dept,SID FROM Port_Emp SELECT No,Name,ParentNo FROM Port_Dept SELECT No,Name, ...

  3. msf generate exec payload

    daniel@daniel-mint ~/msf/metasploit-framework $ ruby msfpayload windows/exec CMD=calc.exe N WARNING: ...

  4. activi7流程部署

    package com.zcc.acvitivi; import org.activiti.engine.ProcessEngine;import org.activiti.engine.Proces ...

  5. C語言中資料結構(struct)的大小

    通常在PC上寫程式時,很少會去管struct會佔掉多少記憶體.當要使用到時,也不會想去用手算到底佔掉多少,大多是直接使用sizeof來做計算.然而sizeof計算出來的值往往不會如我們想的一樣.因為c ...

  6. bat批处理----copy和xcopy区别

    copy和xcopy区别:两者都可以赋值文件 1.copy不能在有子目录存在的文件中拷贝文件的同时重命名此文件名 2.copy命令能合并两个文件,而xcopy不能

  7. Redis哨兵机制(sentinel)

    1.简介: 1.是什么: Redis-Sentinel是Redis官方推荐的高可用(HA)方案,当用Reids 做master-slave高可用方案时,假如master宕机了,redis本身(包括它的 ...

  8. flex布局(弹性布局)

    1. 传统布局与 flex 布局比较 传统布局 兼容性好 布局繁琐 局限性,不能在移动端很好的布局 flex 弹性布局 操作方便,布局极为简单,移动端应用很广泛 PC端浏览器支持较差 IE 11 或 ...

  9. Elasticsearch添加Shield后TransportClient如何连接?

    Elasticsearch添加Shield后TransportClient如何连接? 时间 2015-12-28 10:24:01  旁门左道 原文  http://log.medcl.net/ite ...

  10. jq 将translate的旋转角度转为数值

    // 将translate内的角度转为数值 function getmatrix(nowDeg){ var values = nowDeg.split('(')[1].split(')')[0].sp ...