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 外键字段的增删查改的更多相关文章

  1. DRF 外键字段深度查询优化、ListSerializer辅助完成群改

    目录 一.Response封装 二.外键字段深度查询 1.序列化配置exclude.depth 2.模型层函数.插拔式字段查询 三.listserializer辅助类 一.Response封装 用de ...

  2. 3.EF 6.0 Code-First实现增删查改

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-entity-framework-5-0-code- ...

  3. MongoDB入门学习(三):MongoDB的增删查改

            对于我们这样的菜鸟来说,最重要的不是数据库的管理,也不是数据库的性能,更不是数据库的扩展,而是怎么用好这款数据库,也就是一个数据库提供的最核心的功能,增删查改.         由于M ...

  4. mysql 增删查改

    非关系型数据库关系型数据库Oracle mysql sqlserver db2 Postgresql Sqlite access sqlserver 微软db2 ibm================ ...

  5. 后端Spring Boot+前端Android交互+MySQL增删查改(Java+Kotlin实现)

    1 前言&概述 这篇文章是基于这篇文章的更新,主要是更新了一些技术栈以及开发工具的版本,还有修复了一些Bug. 本文是SpringBoot+Android+MySQL的增删查改的简单实现,用到 ...

  6. 5.在MVC中使用泛型仓储模式和工作单元来进行增删查改

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/crud-operations-using-the-generic-repository-pat ...

  7. hibernate基础增删查改简单实例

    hibernate 基础理论知识网上很多,可以百度和google.这里不做多的介绍,以一个User表来开展例子 建一个web-project 我这里用了junit单元测试环境来进行增删查改的测试,别的 ...

  8. 使用EntityFramework6完成增删查改和事务

    使用EntityFramework6完成增删查改和事务 上一节我们已经学习了如何使用EF连接数据库,并简单演示了一下如何使用EF6对数据库进行操作,这一节我来详细讲解一下. 使用EF对数据库进行操作, ...

  9. [置顶] cocos2dx sqllite 增删查改等操作

    首先导入文件shell.c sqllite3.c sqlite3.h sqlite3etx.h文件(注意在生成安卓项目是 不要将shell.c写进android.mk文件中,写进去在cywin中生成会 ...

随机推荐

  1. Verdi Transaction Debug Mode 简单使用

    转载:Verdi Transaction Debug Mode 简单使用_Holden_Liu的博客-CSDN博客 文档与源码: User Guide: Verdi_Transaction_and_P ...

  2. 20191310李烨龙作业:MySort

    作业:MySort 任务详情 1. 用man sort 查看sort的帮助文档 2. sort常用选项有哪些,都有什么功能?提交相关使用的截图 3. 如果让你编写sort,你怎么实现?写出伪代码和相关 ...

  3. split,cdn,shell脚本,tmux,记一次往国外服务器传大文件的经历

    需求是这样的:将一个大概680M的Matlab数据文件传到国外某所大学的服务器上,服务器需要连接VPN才能访问,由于数据文件太大,而且如果我直接ssh连过去或者用ftp传输,那么中间很可能中断. ps ...

  4. prometheus(1)之核心概念

    个人理解:prometheus核心在于 1.prom数据类型的理解 (4钟数据类型 与常用的promQL语法 其实很容易) 2.各种服务发现与正则拼接(服务发现的拼接其实官方定义好的 理解就行) 3. ...

  5. 【Python+postman接口自动化测试】(6)Chrome开发者工具

    Chrome开发者工具 Elements: HTML元素面板,用于定位查看元素源代码 Console: js控制台面板,js命令行,查看前端日志 Sources: 资源面板,用于断点调试js Netw ...

  6. mysql流程控制结构case when

    一.case 使用场景 简单函数 CASE case_value WHEN when_value THEN statement_list [WHEN when_value THEN statement ...

  7. forceUpdate() & set

    前言 在开发过程中,我们时常会遇到这样一种情况:当vue的data里边声明或者已经赋值过的对象或者数组(数组里边的值是对象)时,向对象中添加新的属性,如果更新此属性的值,是不会更新视图的. 根据官方文 ...

  8. idea连接数据库时区:Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' prope

    错误界面 IDEA连接mysql,地址,用户名,密码,数据库名,全都配置好了,点测试连接,咔!不成功! 界面是这样的, 翻译过来就是:服务器返回无效时区.进入"高级"选项卡,手动设 ...

  9. 写给初学者的Linux errno 错误码机制

    不同于Java的异常处理机制, 当你使用C更多的接触到是基于错误码的异常机制, 简单来说就是当调用的函数发生异常时, 程序不会跳转到一个统一处理异常的地方, 取而代之的是返回一个整型错误码. 可能会有 ...

  10. Linux usb 5. usbip (USB Over IP) 使用实例

    文章目录 0. 简介 1. Server 配置 2. Client 配置 参考资料 0. 简介 USB Over IP 是一种应用很多的场景,目前已经有现成的解决方案 usbip.linux 和 wi ...