Django--ORM 多表查询

2023-11-05

目录

数据准备

正向查询与反向查询

基于对象的跨表查询

正向查询

一对多

多对多

一对一

反向查询

一对多

多对多

一对一

正向查询

反向查询

基于双下线的跨表查询

正向查询

一对一

一对多

多对多

反向查询

一对一

一对多

多对多

双下高阶正反向查询

使用filter()的双下线查询

连续跨多张表查询


数据准备

moduls.py

# 构建表结构
from django.db import models

# 表app01_publish
class Publish(models.Model):
    name = models.CharField(max_length=20)
    addr = models.CharField(max_length=20)

# 表app01_author_detail
class Author_Detail(models.Model):
    tel = models.CharField(max_length=20)

# 表app01_author
class Author(models.Model):
    name = models.CharField(max_length=20)
    age = models.IntegerField()

    # 表app01_author一对一表app01_authordetail
    detail = models.OneToOneField(to='Author_Detail',to_field='id',unique=True,on_delete=models.CASCADE)


# 表app01_book
class Book(models.Model):
    title = models.CharField(max_length=20)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    pub_date = models.DateField(auto_now_add=True)

    # 表app01_book多对一表app01_publish,参数to指定模型名,参数to_field指定要关联的那个字段
    publish = models.ForeignKey(to='Publish',to_field='id',on_delete=models.CASCADE)

    # 我们自己写sql时,针对书籍表与作者表的多对关系,需要自己创建新表,而基于django的orm,下面这一行代码可以帮我们自动创建那张关系表
    authors=models.ManyToManyField(to='Author')
    # 变量名为authors,则新表名为app01_book_authors,若变量名为xxx,则新表名为app01_book_xxx

tests.py

# 添加数据

import os

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "book_sys.settings")
    import django
    django.setup()

    from app01.models import *
    # 1、先添加没有外键字段的 author_detail表 pubulish表
    Author_Detail.objects.create(tel='123456789')
    Author_Detail.objects.create(tel='987654321')
    Author_Detail.objects.create(tel='000000000')

    Publish.objects.create(name='北方出版社',addr='北京')
    Publish.objects.create(name='南方出版社',addr='南京')
    Publish.objects.create(name='东方出版社',addr='上海')
    Publish.objects.create(name='西方出版社',addr='西安')

    # 2、添加 author表 book表
    Author.objects.create(name='frank',age=31 ,detail_id=1)
    Author.objects.create(name='lili',age=29 ,detail_id=2)
    Author.objects.create(name='tank',age=42 ,detail_id=3)

    Book.objects.create(title='三国演义',price=200 ,publish_id=1)
    Book.objects.create(title='三国志',price=198.5 ,publish_id=2)
    Book.objects.create(title='红楼梦',price=255.43 ,publish_id=2)
    Book.objects.create(title='西游记',price=300.5 ,publish_id=3)
    Book.objects.create(title='西厢记',price=213.4 ,publish_id=4)
    Book.objects.create(title='水浒传',price=199 ,publish_id=1)

    # 3、最后操作 author_book表,由于使用的是 ManyToMany 字段自动生成的,所以要基于外键所在的表进行操作
    book_obj1=Book.objects.filter(pk=1).first()
    book_obj1.authors.add(1,2)

    book_obj2 = Book.objects.filter(pk=2).first()
    book_obj2.authors.add(1)

    book_obj3 = Book.objects.filter(pk=3).first()
    author_obj1 = Author.objects.filter(pk=1).first()
    author_obj2 = Author.objects.filter(pk=2).first()
    book_obj3.authors.add(author_obj1,author_obj2)

    book_obj4 = Book.objects.filter(pk=4).first()
    book_obj4.authors.add(3,2)

    book_obj5 = Book.objects.filter(pk=5).first()
    book_obj5.authors.add(3)

    book_obj6 = Book.objects.filter(pk=6).first()
    book_obj6.authors.add(1,3)

正向查询与反向查询

一出版社和书籍为例, 书记表含有出版社表的外键字段

正向查询>>> 书籍查询出版社

反向查询>>> 出版社查询书籍

总结: 当前查询对象是否含有外键字段, 有就是正向查询, 没有就是反向查询

正向查询按照字段查询, 反向查询按照表名查询

基于对象的跨表查询

相当于MySQL中的子查询: 将一张表的查询结果用括号括起来, 当作另一条SQL语句的条件 . 

正向查询

一对多

查询书籍主键为5 的出版社名称

1. 查主键为5的书籍对象

2. 根据书籍对象的外键字段 publish 获取到出版社对象

3. 由出版社对象获取到名称

book_obj = Book.objects.filter(pk=5).first()
res = book_obj.publish
print(res)
# Publish object
print(res.name)
# 西方出版社

多对多

查询书籍主键为3的作者姓名

1. 查询书籍主键为3的书籍对象

2. 外键字段在书籍表中, 同样是正向查询,那么只需要按照字段autjors查询即可

3. 获取作者对象的姓名

book_obj = Book.objects.filter(pk=3).first()
res = book_obj.authors
print(res)
# app01.Author.None

注意: 由于字段authors 是多对多的外键字段, 此时拿到的对象还需要进一步的操作

book_obj = Book.objects.filter(pk=3).first()
res = book_obj.authors

res1 = book_obj.authors.all()
print(res1)
# <QuerySet [<Author: Author object>, <Author: Author object>]>

然后再for循环各自的姓名即可

一对一

查询作者lili的号码

1.查询作者对象

2,外键字段再作者表中, 同样是正向查询,那么只需要按照字典detail查询即可

3. 获取详情对象的tel

author_obj = Author.objects.filter(name='lili').first()
res = author_obj.detail
print(res)
print(res.tel)

反向查询

一对多

查询东方出版社出版的书籍

1. 先获取东方出版社的对象

2. 出版社没有外键字段, 去查书籍是反向查询

3. 表名小写_set.all()

4. 获取书籍名称

publish_obj=Publish.objects.filter(name='东方出版社').first()
print(publish_obj)
# Publish object

res = publish_obj.book_set
print(res)
# app01.Book.None

res1 = res.all()
print(res1)
# <QuerySet [<Book: Book object>]>
for obj in res1:
  print(obj.title)

多对多

查询作者lili写过的书籍

1.获取作者对象

2. 作者表中没有书籍表的外键, 所以是反向查询

3. .book_set.all()获取书籍对象

4. 再获取书籍对象的名称

author_obj = Author.objects.filter(name='lili').first()
res = author_obj.book_set
print(res)
# app01.Book.None
res1 = res.all()
print(res1)
# <QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>]>
for obj in res1:
  print(obj.title, end='')
# 三国演义,红楼梦,西游记,

一对一

查询号码为0000000的作者

1. 查询作者对象详情

2.外键字段在作者表中, 同样是证词昂查询, 那么只需要按照字段detail 查询即可

3. 获取详情对象的tel 

detail_obj = Author_Detail.objects.filter(tel='000000000').first()
print(detail_obj)
# Author_Detail object
res = detail_obj.author
print(res)
# Author object
print(res.name)
# tank

方法总结

正向查询

一对一, 一对多的方法是一样的, 按照字段查询就能够直接找到对象 --- author_obj.detail

一对多 , 按照字段查询后会返回一个.None的对象, 需要在字段后面加上.all()>>> book_obj.authors.all()

反向查询

一对多,多对多的方法是一样的, 按照表名小写, 在跟上_set.all()>>>author_obj.book_set.all()

一对一, 则直接按照表明小写, 能够直接拿到>> > detail_obj.author

当查询到的结果中最后以.None结尾, 都需要在原来的查询方法后面在跟上.all()才能获得想要的结果

基于双下线的跨表查询

相当于MySQL中的连表查询: 将两张表或者对账表连成一张表进行查询

正向查询

正向查询, 按照关联字段+双下线>>> .values('关联字段__被关联表中的字段'), 返回的是一个QuerySet对象

一对一

查询作者frank的手机号

res = Author.objects.filter(name='frank').values('detail__tel')
print(res)
# <QuerySet [{'detail__tel': '123456789'}]>

print(res.first())
# {'detail__tel': '123456789'}

一对多

查询三国演义的出版社名字

res = Book.objects.filter(title='三国演义').values('publish__name')
print(res)
print(res.first())

# <QuerySet [{'publish__name': '北方出版社'}]>
# {'publish__name': '北方出版社'}

多对多

查询三国演义的所有作者

res = Book.objects.filter(title='三国演义').values('authors__name')
print(res)
# <QuerySet [{'authors__name': 'frank'}, {'authors__name': 'lili'}]>

反向查询

按模型名(小写)+双下线>>> .values('表名小写__被关联表中的字段'), 返回的是一个QuerySet对象. 

一对一

查询手机号为'123456789'的作者名

res = Author_Detail.objects.filter(tel='123456789').values('author__name')
print(res)
# <QuerySet [{'author__name': 'frank'}]>

一对多

查询北方出版社出版的所有书籍名字

res = Publish.objects.filter(name='北方出版社').values('book__title')
print(res)
# <QuerySet [{'book__title': '三国演义'}, {'book__title': '水浒传'}]>

多对多

查询lili出版的所有书籍

res = Author.objects.filter(name='lili').values('book__title')
print(res)
# <QuerySet [{'book__title': '三国演义'}, {'book__title': '红楼梦'}, {'book__title': '西游记'}]>

方法总结:

正向查询,按关联字段: .values('关联字段__被关联表中的字段'), 返回的是一个QuerySet对象

按模型名(小写)+双下线: .values('表名小写__被关联表中的字段'), 返回的是一个QuerySet对象, 对象中保存的是字典类型的数据

双下高阶正反向查询

使用filter()的双下线查询

首先需要考虑的是正向查询还是反向查询, 确定括号内使用的方法, 但是括号外面不是使用values,而是使用filter!!!

注意: 使用filter方法字段是不能加引号的, values需要加引号

查询书籍主键为反向, 使用.filter('表名小写__被关联表中的字段')

res = Publish.objects.filter(book__pk= 4)
print(res)

# <QuerySet [<Publish: Publish object>]>
res = Publish.objects.filter(book__title= '西游记')
print(res)
# 结果相同

连续跨多张表查询

套路与上面的案例都是一样的, 可以练习n个双下划线, 只需要在每次双下线的时候, 确定是每个双下线后面是正向查询还是反向查询即可

# 需求1:查询北京出版社出版过的所有书籍的名字以及作者的姓名、手机号
# 方式一:基表为Publish
res=Publish.objects.filter(name='北方出版社').values_list('book__title','book__authors__name','book__authors__author_detail__tel')

# 方式二:基表为Book
res=Book.objects.filter(publish__name='北方出版社').values_list('title','authors__name','authors__author_detail__tel')

# 循环打印结果均为
for obj in res:
    print(obj)



# 需求2:查询手机号以186开头的作者出版过的所有书籍名称以及出版社名称
# 方式一:基表为AuthorDetail
res=AuthorDetail.objects.filter(tel__startswith='186').values_list('author__book__title','author__book__publish__name')

# 方式二:基表为Book
res=Book.objects.filter(authors__author_detail__tel__startswith='186').values_list('title','publish__name')

# 方式三:基表为Publish
res=Publish.objects.filter(book__authors__author_detail__tel__startswith='186').values_list('book__title','name')

# 循环打印结果均为
for obj in res:
    print(obj)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Django--ORM 多表查询 的相关文章

随机推荐

  • python输出日志到文件_python将print输出的信息保留到日志文件中

    具体代码如下所示 import sys import os import sys import io import datetime def create detail day return 年 月 日 daytime datetime d
  • 通过白噪声的频谱处理产生任意光谱斜率(f^a)噪声(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码及文章讲解 1 概述 文献来源 摘要 本文研究了具有任意谱
  • 前端例程20220815:拟物风格复选按钮

    演示 原理 本文要实现的按钮大致示意如下 观察者从正上方观看 写代码时主要处理光照以及近大远小等现象 代码
  • 【css】将背景图片设置到元素的右上角

    p 科学熊 将背景图片设置到body元素的右上角 p 效果 background repeat no repeat 设置背景是否重复显示 no repeat为不重复 r
  • java POI解析获取word文件内容

    1 需要的pom文件依赖
  • 微信小程序一键授权之前勾选协议

    微信小程序授权获取手机号之前勾选我已阅读并同意协议 想要实现的效果 用户点击微信一键注册按钮 如果用户没有勾选协议 就提示请勾选用户协议 如果勾选了 就直接获取微信用户的手机号密文 开始想的是直接在getPhoneNumber 方法中加一个
  • python同时发大量请求_PythonWebServer如何同时处理多个请求

    对于初学Web开发 理解一个web server如何能同事处理多个请求很重要 当然更重要的是 理解你通过浏览器发送的请求web server是怎么处理的 然后怎么返回给浏览器 浏览器才能展示的 我到现在还记得大概在2010年左右 看了tom
  • 高德地图的缩放和位移监听

    最近项目采用高德地图 高德地图的文档 demo都很详细 想实现的功能基本上都有 在项目里有一个功能 是类似根据地图的中心经纬度实现数据请求 为了不无限的请求 所以要分别监听 地图的缩放 地图位移 这里就有一个方法 gadMap setOnC
  • matlab根据成绩划分等级_Excel数据分析必备技能:对数据按范围多条件划分等级的判定套路

    点击右上角 关注 每天免费获取干货教程 职场办公中经常要对数据进行整理和分析 其中等级归类划分是很常用的一种方法 在这个过程中用好Excel公式可以事半功倍 但是还是有很多人不了解在Excel中对数据按范围多条件划分等级的系统思路和方法 所
  • Cover Letter常用范式和模版

    摘自 https zhuanlan zhihu com p 26708261 http muchong com html 201401 6920446 html 1 什么是Cover letter Cover Letter 即投稿信 是论文
  • 深聊测开领域之:测试策略模型有哪些?

    测试模型的分类 1 引言 2 金字塔 2 1 金字塔模型 引入 2 2 金字塔弊端 2 3 金字塔图形 3 冰淇淋 3 1 冰淇淋模型 引入 3 2 冰淇淋模型 优缺点 3 2 1 缺点 3 2 2 优点 3 2 冰淇淋图形 4 冠军杯 4
  • 微信小程序面试题汇总

    HTML篇 CSS篇 JS篇 Vue篇 TypeScript篇 React篇 前端面试题汇总大全 含答案超详细 HTML JS CSS汇总篇 持续更新 前端面试题汇总大全二 含答案超详细 Vue TypeScript React Webpa
  • 环境变量知识点

    环境变量 环境变量 环境变量是用来定义系统运行环境的一些参数 比如说 每一个用户的家目录 echo HOME 还有我们在编写C C 代码的时候 在链接的时候 从来不知道我们的所链接的动态静态库在哪里 但是照样可以链接成功 生成可执行程序 原
  • 不使用采集卡,实现相机手机多机位直播

    背景 因为直播需求 现在想实现使用一台相机和一台手机完成直播的两个机位设定 搜了很多视频都是要购买采集卡 违背了性价比这一原则 搜索半天之后 根据当前的设备完成了任务 硬件材料 苹果手机一部 佳能单反 所需软件 1 OBS 主要是用来集成各
  • 刷脸让商家引入智慧经营实现数字化转型

    移动支付在生活中已经实现了全覆盖 从单一的支付到驱动智慧经营 在数据为王的时代 通过对移动支付数据的深度挖掘 整合成消费大数据 移动支付还在经营上改变商户的效率 从以前柜台结账到如今的自助结账 从人工推荐到大数据的精准推荐 彻底的改变了商户
  • Linux make --强大的编译工具

    用途说明 make命令是一个常用的编译命令 尤其是在开发C C 程序时 它通过Makefile文件中描述的源程序之间的依赖关系来自动进行编译 Makefile文件是按照规定的格式编写的 文件中需要说明如何编译各个源文件并连接生成可执行文件
  • CVE-2020-11444:Nexus Repository Manager 3 远程命令执行漏洞

    读者需知 本文仅供学习使用 由于传播和利用此文所造成的损失均由使用者本人负责 文章作者不为此承担责任 简介 Nexus Repository是一个开源的仓库管理系统 可搭建npm maven等私服 Nexus 3 任意修改admin密码越权
  • Socket错误详解及处理方法

    例如错误代码10061 说明服务器已经找到 但连接被服务器拒绝 连接失败原因可能是 端口号设置错误 2 服务器没有处于监听状态 即ServerSocket gt Active true 3 数据包被服务器端的防火墙过滤掉 附 Socket常
  • Qt 连接、操作数据库(增删改查)

    文章目录 Qt 5 9连接MySQL5 7 32 64位 操作数据库 QSqlQuery类 执行SQL语句 查 浏览结果集方法 增 删 改 事务 Qt 5 9连接MySQL5 7 32 64位 MySQL5 7安装好后将其安装路径lib下
  • Django--ORM 多表查询

    目录 数据准备 正向查询与反向查询 基于对象的跨表查询 正向查询 一对多 多对多 一对一 反向查询 一对多 多对多 一对一 正向查询 反向查询 基于双下线的跨表查询 正向查询 一对一 一对多 多对多 反向查询 一对一 一对多 多对多 双下高