day08 外键字段的增删查改
day08 外键字段的增删查改
今日内容概要
- 外键字段的增删查改
- 正反向查询的概念
- 基于对象的跨表查询(子查询)
- 基于双下划线的跨表查询(连表操作)
- 聚合查询与分组查询
- F查询和Q查询
前提准备
class Books(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') # 一对多
author = 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',null=True)
class AuthorDetail(models.Model): # 作者详情
phone = models.BigIntegerField()
addr = models.CharField(max_length=32)
外键字段的增删查改
针对一对一、一对多字段操作
# 增的两种方式
1、直接增加
models.Books.objects.create(title='圣王',price=111.11,publish_id=1)
2、使用对象增加
publish_obj = models.Publish.objects.filter(pk=2).first() # 出版社对象
models.Books.objects.create(title='阳神',price=222.22,publish=publish_obj)
# 改的两种方式
1、直接修改
models.Books.objects.filter(pk=2).update(publish_id=1)
2、使用对象修改
publish_obj = models.Publish.objects.filter(pk=2).first() # 出版社对象
models.Books.objects.filter(pk=1).update(publish=publish_obj) # 把书籍1改成出版社2
针对多对多字段操作
'''
多对多中向第三张表增加数据用:add
多对多中向第三张表修改数据用:set
'''
# 增(虚拟的第三张表)
1、直接增加
book_obj = models.Books.objects.filter(pk=2).first() # 书籍2的和作者1关联
book_obj.author.add(1)
book_obj.author.add(1,2) # 书籍也可以关联多个作者
2、使用对象增加
book_obj = models.Books.objects.filter(pk=1).first() # 书籍1的对象
author_obj = models.Author.objects.filter(pk=2).first() # 作者2的对象
book_obj.author.add(author_obj) # 书籍1关联作者2的对象,也可以放多个作者对象
'''
总结:add在第三张关系表中添加数据,
括号内既可以传主键字段也可以传数据对象,并且支持传多个
'''
# 改
1、直接修改
book_obj = models.Books.objects.filter(pk=2).first() # 书籍2的的对象
book_obj.author.set([2,]) # 书籍1的作者改成作者2
# 注:set后面必须是可迭代对象,比如列表,元祖
2、使用对象修改
book_obj = models.Books.objects.filter(pk=2).first() # 书籍2的的对象
author_obj = models.Author.objects.filter(pk=1).first() # 作者1的对象
book_obj.author.set([author_obj]) # 把书籍2绑定的作者2改成作者1
'''
总结:set 在第三张关系表中修改数据
括号内需要传一个可迭代对象
可迭代对象里面的元素既可以传主键字段,也可以传数据对象,并且支持传多个
'''
# 删
1、直接删除
book_obj = models.Books.objects.filter(pk=2).first() # 书籍2的的对象
book_obj.author.remove(1) # 移除书籍2绑定的作者1的数据
2、使用对象修改
book_obj = models.Books.objects.filter(pk=2).first() # 书籍2的的对象
author_obj = models.Author.objects.filter(pk=2).first() # 作者2的对象
book_obj.author.remove(author_obj) # 把书籍2绑定给作者2的数据移除
'''
总结:remove:
在第三张表关系中删除数据
括号内既可以传主键字段也可以传数据对象,并且支持传多个
'''
3、清空所有数据
book_obj = models.Books.objects.filter(pk=2).first() # 书籍2的的对象
book_obj.author.clear() # 清空书籍2的所有绑定关系
'''
总结:clear
在第三张表关系中清空所有的数据,并且括号内无需传值
'''
正反向理论
'''
多对多外键、一对多外键建在books表中
一对一外键建在author表中
'''
正向查询
书籍对象查出版社对象 外键字段在书表中 # 正向查询
书籍对象查作者对象 外键字段在书表中 # 正向查询
作者对象查作者详情 外键字段在作者中 # 正向查询
反向查询
出版社查书籍对象 外键字段不在出版社表中 # 反向查询
作者查书籍对象 外键字段不在作者表中 # 反向查询
作者详情查作者 外键字段不在作者详情表中 # 反向查询
"""
查询数据的时候如果外键字段"在你的手上"则为正向查询
如果外键字段不在则为反向查询
"""
*****************************************重要******************************************
# 口诀:
正向查询按外键字段 ... # 当关联多个时,后面加上.all()
反向查询按表名小写 ... # 当关联多个时,表名小写加上_set.all()
基于对象的跨表查询(子查询)正向查询
什么是子查询
将一条SQL语句的查询结果当做另外一条SQL语句的查询条件
# 基于对象的跨表查询(分步查询)
案例1:查询主键为2的书籍对应的出版社
# 先查询书籍对象
book_obj = models.Books.objects.filter(pk=2).first()
# 再基于书籍对象查询出版社对象(书跟出版社的外键字段在书中 所以为正向)
res = book_obj.publish
print(res.name)
案例2:查询主键为3的书籍对应的作者
# 先查询书籍对象
book_obj = models.Books.objects.filter(pk=3).first()
# 再基于书籍对象查询作者对象(书跟作者的外键字段在书中 所以为正向)
res = book_obj.author.all() # 当多个值时,要加上all()
print(res) # <QuerySet [<Author: 老鹰吃小鸡>, <Author: 我爱吃西红柿>]>
for author_name in res:
print(author_name.name)
案例3:查询作者"老鹰吃小鸡"的详情数据
author_obj = models.Author.objects.filter(name="老鹰吃小鸡").first() # 作者详情
res = author_obj.author_detail # 正向查询按字段名
print(res,res.phone)
'''
总结:
基于对象的正向查询,数据对象点了外键之后
是否需要再点all,取决于关联的数据项有几个,单个无需点,多个则需要点
'''
基于对象的跨表查询(反向查询)
案例1:查询东方出版社出版的书籍
# 先查询东方出版社对象
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
# 基于东方出版社对象对象查询书籍对象(东方出版社对象跟书籍的外键字段在书籍表中 所以为反向)
res = publish_obj.books_set.all()
print(res) # <QuerySet [<Books: 阳神>, <Books: 完美世界>]>
案例2:查询作者"老鹰吃小鸡"写过的书籍
author_obj = models.Author.objects.filter(name='老鹰吃小鸡').first()
res = author_obj.books_set.all()
print(res)
案例3:查询电话是111的作者姓名
author_detail_obj = models.AuthorDetail.objects.filter(phone=111).first()
res = author_detail_obj.author
print(res)
'''
总结:
如果查询出来的数据对象可以有多个,需要加上:表名小写_set.all()
如果查询出来的数据对象只有一个,表名小写
'''
基于双下划线的跨表查询(连表操作)
# 双下划线的用法:values里面根据外键字段去到哪个表,如果要取那个字段,直接__字段名。
'''
values():指定查询字段,返回的列表套字典
values_list():指定查询字段,返回的是列表套元祖
'''
案例1:主键为2的书籍对应的出版社
# 主键2的书籍对象,根据外键字段去到publish表中查找name字段
res = models.Books.objects.filter(pk=2).values('publish__name') # 正向查询
print(res) # <QuerySet [{'publish__name': '东方出版社'}]>
案例2:查询主键为3的书籍对应的作者
res = models.Books.objects.filter(pk=3).values('author__name') # 正向查询
print(res) # <QuerySet [{'author__name': '老鹰吃小鸡'}]>
案例3:查询作者"老鹰吃小鸡"的详情数据
res = models.Author.objects.filter(name='老鹰吃小鸡').values('author_detail__phone','author_detail__addr') # 正向查询
print(res)
# <QuerySet [{'author_detail__phone': 111, 'author_detail__addr': '厦门'}]>
案例4:查询书籍pk为2的作者的电话
res = models.Books.objects.filter(pk=2).values('author__name','author__author_detail__phone')
print(res)
# <QuerySet [{'author__name': '我爱吃西红柿', 'author__author_detail__phone': 222}]>
'''
总结:
使用双下划线查询比较方便,代码简洁
values():指定查询字段
values()里面可以一直根据外键字段点下去,然后在查找需要的字段
'''
基于双下划线的跨表查询(反向查询)
# 双下划线的用法:values里面根据表名小写去到哪个表,如果要取那个字段,直接__字段名。
案例1:查询东方出版社出版的书籍
# 基于东方出版社对象对象查询书籍对象(东方出版社对象跟书籍的外键字段在书籍表中 所以为反向)
res = models.Publish.objects.filter(name='东方出版社').values('books__title')
print(res) # 反向查询:表名小写
案例2:查询作者"老鹰吃小鸡"写过的书籍
res = models.Author.objects.filter(name='老鹰吃小鸡').values('books__title')
print(res)
案例3:查询电话是111的作者姓名
res = models.AuthorDetail.objects.filter(phone=111).values('author__name')
print(res)
双下划线进阶操作
1、查询主键为2的书籍对应的出版社(不能点书籍) # 所以只能点出版社
res = models.Publish.objects.filter(books__pk=2) # 拿到书籍2的对应出版社
print(res)
2、查询主键为3的书籍对应的作者
res = models.Author.objects.filter(books__pk=3) # 拿到书籍的对应作者
print(res)
3、查询东方出版社出版的书籍
res = models.Books.objects.filter(publish__name='东方出版社') # 拿到东方出版社的书籍
print(res)
4、查询作者"老鹰吃小鸡"的写过的书籍
res = models.Books.objects.filter(author__name='老鹰吃小鸡')
print(res)
5、查询电话是111的作者姓名
res = models.Author.objects.filter(author_detail__phone=111)
print(res) # <QuerySet [<Author: 老鹰吃小鸡>]>
'''
总结:
代码相比其他更简便
由没有条件的表来查询有条件的表
'''
聚合查询
集合函数:
max min sum count avg
# 聚合函数在SQL语句是要配合分组使用的,在这里要想使用,需要aggregate
from django.db.models import Max,Min,Sum,Count,Avg # 导模块
1、统计所有书籍的总价格
res = models.Books.objects.aggregate(Sum('price')) # 需要使用aggregate
print(res)
2、统计所有书籍的总数
res = models.Books.objects.aggregate(Count('pk')) # 根据id来统计
print(res)
3、统计价格最高的
res = models.Books.objects.aggregate(Max('price')) # 也可以放多个聚合
res = models.Books.objects.aggregate(Max('price'),Min('price'))
print(res)
分组查询
# 在哪张表就在哪里分组
'''author_num是必须要起的别名 因为后面的values中需要使用'''
1、统计每一本书的作者个数
res = models.Books.objects.annotate
(author_num=Count('author__pk')).values('author_num', 'title')
2、统计出每个出版社卖的最便宜的书的价格
# 先根据主板社分组,之后再拿到便宜的书。
res = models.Publish.objects.annotate(min_price=Min('books__price')).values('min_price','name')
print(res)
3、统计不止一个作者的图书
# 先根据书分组,然后在拿到作者,之后过滤图书作者大于1的
res = models.Books.objects.annotate(author_num=Count('author__pk')).filter(author_num__gt=1)
print(res)
4、查询各个作者出的书的总价格
res = models.Author.objects.annotate(price_sum=Sum('books__price')).values('price_sum','name')
print(res)
# <QuerySet [{'name': '老鹰吃小鸡', 'price_sum': Decimal('888.88')}, {'name': '我爱吃西红柿', 'price_sum': Decimal('666.66')}]>
# 总结:
1.value里面的参数对应的是sql语句中的select要查找显示的字段
2.filter里面的参数相当于where或者having里面的筛选条件
3.annotate本身表示group by的作用,前面找寻分组依据,内部放置显示可能用到的聚合运算式,后面跟filter来增加限制条件,最后的value来表示分组后想要查找的字段值
F与Q查询
# F的功能是获取数据库中字段原有的数据,并且F查询主要操作数字类型的数据。
1、将所有书籍的价格提升100块
models.Books.objects.update(price=F('price')+1000) # F把书籍中price数据都拿出来加1000
2、将所有书籍名称后面加上爆款后缀
from django.db.models.functions import Concat
from django.db.models import Value
models.Books.objects.update(title=Concat(F('title'),Value('爆款')))
# F查询要想操作字符串类型,需要导入上述的两个模块
3、查询库存数大于卖出数的书籍
res = models.Books.objects.filter(kucun__gt=F('maichu'))
print(res)
'''
总结:
F查询主要是操作数字数据的,要想操作字符需要导入两个模块
Concat表示进行字符串的拼接操作,参数位置决定了拼接是在头部拼接还是尾部拼接,Value里面是要新增的拼接值
比值的时候,可以先拿一个条件比,再使用F获取另外一个条件数据
'''
Q查询
"""Q查询"""
# filter括号内多个条件均为and关系
1.查询主键为3或者卖出数为1000的数据
res = models.Book.objects.filter(pk=3, maichu=1000) # 逗号分隔为and关系
from django.db.models import Q
###########基本用法###########
res = models.Book.objects.filter(Q(pk=3), Q(maichu=1000)) # 逗号分隔为and关系
res = models.Book.objects.filter(Q(pk=3) | Q(maichu=1000)) # |分隔为or关系
res = models.Book.objects.filter(~Q(pk=3) | Q(maichu=1000)) # ~分隔为not关系
print(res)
###########进阶用法###########
filter(title='123') filter('title'='123')
q = Q() # 默认多个条件之间也是and关系
q.connector = 'or' # 也可以修改链接关系
q.children.append(('title', '三国演义爆款'))
q.children.append(('title__contains', '爆'))
q.children.append(('price', 1123))
res = models.Book.objects.filter(q)
print(res)
'''
总结:
用Q查询包起来条件,可以使用成员关系运算符
, 为 and
| 为 or
~ 为 not
'''
day08 外键字段的增删查改的更多相关文章
- DRF 外键字段深度查询优化、ListSerializer辅助完成群改
目录 一.Response封装 二.外键字段深度查询 1.序列化配置exclude.depth 2.模型层函数.插拔式字段查询 三.listserializer辅助类 一.Response封装 用de ...
- 3.EF 6.0 Code-First实现增删查改
原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-entity-framework-5-0-code- ...
- MongoDB入门学习(三):MongoDB的增删查改
对于我们这样的菜鸟来说,最重要的不是数据库的管理,也不是数据库的性能,更不是数据库的扩展,而是怎么用好这款数据库,也就是一个数据库提供的最核心的功能,增删查改. 由于M ...
- mysql 增删查改
非关系型数据库关系型数据库Oracle mysql sqlserver db2 Postgresql Sqlite access sqlserver 微软db2 ibm================ ...
- 后端Spring Boot+前端Android交互+MySQL增删查改(Java+Kotlin实现)
1 前言&概述 这篇文章是基于这篇文章的更新,主要是更新了一些技术栈以及开发工具的版本,还有修复了一些Bug. 本文是SpringBoot+Android+MySQL的增删查改的简单实现,用到 ...
- 5.在MVC中使用泛型仓储模式和工作单元来进行增删查改
原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pat ...
- hibernate基础增删查改简单实例
hibernate 基础理论知识网上很多,可以百度和google.这里不做多的介绍,以一个User表来开展例子 建一个web-project 我这里用了junit单元测试环境来进行增删查改的测试,别的 ...
- 使用EntityFramework6完成增删查改和事务
使用EntityFramework6完成增删查改和事务 上一节我们已经学习了如何使用EF连接数据库,并简单演示了一下如何使用EF6对数据库进行操作,这一节我来详细讲解一下. 使用EF对数据库进行操作, ...
- [置顶] cocos2dx sqllite 增删查改等操作
首先导入文件shell.c sqllite3.c sqlite3.h sqlite3etx.h文件(注意在生成安卓项目是 不要将shell.c写进android.mk文件中,写进去在cywin中生成会 ...
随机推荐
- linux中的strip命令简介
转载:https://blog.csdn.net/qq_37858386/article/details/78559490 strip:去除,剥去 一.下面是man strip获得到的信息,简 ...
- python re:正则表达式中使用变量
参考:https://www.cnblogs.com/songbiao/p/12422632.html Python中正则表达式的写法,核心就是一个字符串.如下:re.compile(r'表达式')所 ...
- error: ‘int64_t’ does not name a type
我在CodeBlock中编译工程没有出现问题,但是放到ubuntu上用自己写的Makefile make的时候报错 error: 'int64_t' does not name a type # 2 ...
- linux下创建文件的文件权限问题
今天发现创建文件的权限和自己规定的权限不一致,了解到了权限掩码的问题,这里总结一下. 首先权限掩码umask是chmod配套的,总共为4位(gid/uid,属主,组权,其它用户的权限),不过通常我们都 ...
- hdu 2086 A1 = ? (公式推导)
有如下方程:Ai = (Ai-1 + Ai+1)/2 - Ci (i = 1, 2, 3, .... n).若给出A0, An+1, 和 C1, C2, .....Cn.请编程计算A1 = ? Inp ...
- mybatis之参数传递的方式 | mybatis
1.单个参数(基本类/包装类+String) 这种情况MyBatis可直接使用这个参数,不需要经过任何处理. 一个参数情况下#{}中内容随便写 public Employee getEmployeeB ...
- 1. 处理静态资源 2. controller如何接受请求得参数 3. 如何把controller得数据保存到view. 4. 在controller如何完成重定向到指定路径 5. controller返回json数据
1. 1. 处理静态资源2. controller如何接受请求得参数3. 如何把controller得数据保存到view.4. 在controller如何完成重定向到指定路径5. controller ...
- 3组-Alpha冲刺-2/6
一.基本情况 队名:发际线和我作队 组长博客:链接 小组人数:10 二.冲刺概况汇报 黄新成(组长) 过去两天完成了哪些任务 文字描述 在校内外进行了数据采集,采集了多场景的数据,并进行了帧分割. 展 ...
- C++内存管理剖析
C++内存管理 C++中有四种内存分配.释放方式: 最高级的是std::allocator,对应的释放方式是std::deallocate,可以自由设计来搭配任何容器:new/delete系列是C++ ...
- python读写文件with open
简介 使用python的过程中肯定少不了读取文件的操作, 传统的形式是使用 直接打开.然后在操作.然后再关闭, 这样代码量稍微大些不说,一旦在操作步骤中出现报错,则无法进行文件的关闭: 案例一(读取) ...