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中生成会 ...
随机推荐
- Verdi Transaction Debug Mode 简单使用
转载:Verdi Transaction Debug Mode 简单使用_Holden_Liu的博客-CSDN博客 文档与源码: User Guide: Verdi_Transaction_and_P ...
- 20191310李烨龙作业:MySort
作业:MySort 任务详情 1. 用man sort 查看sort的帮助文档 2. sort常用选项有哪些,都有什么功能?提交相关使用的截图 3. 如果让你编写sort,你怎么实现?写出伪代码和相关 ...
- split,cdn,shell脚本,tmux,记一次往国外服务器传大文件的经历
需求是这样的:将一个大概680M的Matlab数据文件传到国外某所大学的服务器上,服务器需要连接VPN才能访问,由于数据文件太大,而且如果我直接ssh连过去或者用ftp传输,那么中间很可能中断. ps ...
- prometheus(1)之核心概念
个人理解:prometheus核心在于 1.prom数据类型的理解 (4钟数据类型 与常用的promQL语法 其实很容易) 2.各种服务发现与正则拼接(服务发现的拼接其实官方定义好的 理解就行) 3. ...
- 【Python+postman接口自动化测试】(6)Chrome开发者工具
Chrome开发者工具 Elements: HTML元素面板,用于定位查看元素源代码 Console: js控制台面板,js命令行,查看前端日志 Sources: 资源面板,用于断点调试js Netw ...
- mysql流程控制结构case when
一.case 使用场景 简单函数 CASE case_value WHEN when_value THEN statement_list [WHEN when_value THEN statement ...
- forceUpdate() & set
前言 在开发过程中,我们时常会遇到这样一种情况:当vue的data里边声明或者已经赋值过的对象或者数组(数组里边的值是对象)时,向对象中添加新的属性,如果更新此属性的值,是不会更新视图的. 根据官方文 ...
- idea连接数据库时区:Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' prope
错误界面 IDEA连接mysql,地址,用户名,密码,数据库名,全都配置好了,点测试连接,咔!不成功! 界面是这样的, 翻译过来就是:服务器返回无效时区.进入"高级"选项卡,手动设 ...
- 写给初学者的Linux errno 错误码机制
不同于Java的异常处理机制, 当你使用C更多的接触到是基于错误码的异常机制, 简单来说就是当调用的函数发生异常时, 程序不会跳转到一个统一处理异常的地方, 取而代之的是返回一个整型错误码. 可能会有 ...
- Linux usb 5. usbip (USB Over IP) 使用实例
文章目录 0. 简介 1. Server 配置 2. Client 配置 参考资料 0. 简介 USB Over IP 是一种应用很多的场景,目前已经有现成的解决方案 usbip.linux 和 wi ...