Django 第十一课 -- ORM - 多表实例

news2024/9/23 21:28:18

目录

一. 前言

二. 创建模型

三. 插入数据

四. ORM - 添加数据

4.1. 一对多(外键 ForeignKey)

4.2. 多对多(ManyToManyField):在第三张关系表中新增数据

4.3. 关联管理器(对象调用)

五. ORM 查询

5.1. 一对多

5.2. 一对一

5.3. 多对多

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

6.1. 一对多

6.2. 多对多

6.3. 一对一


一. 前言

表与表之间的关系可分为以下三种:

  • 一对一: 一个人对应一个身份证号码,数据字段设置 unique。
  • 一对多: 一个家庭有多个人,一般通过外键来实现。
  • 多对多: 一个学生有多门课程,一个课程有很多学生,一般通过第三个表来实现关联。

二. 创建模型

接下来我们来看下多表多实例。

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    pub_date = models.DateField()
    publish = models.ForeignKey("Publish", on_delete=models.CASCADE)
    authors = models.ManyToManyField("Author")


class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=64)
    email = models.EmailField()


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.SmallIntegerField()
    au_detail = models.OneToOneField("AuthorDetail", on_delete=models.CASCADE)


class AuthorDetail(models.Model):
    gender_choices = (
        (0, "女"),
        (1, "男"),
        (2, "保密"),
    )
    gender = models.SmallIntegerField(choices=gender_choices)
    tel = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)
    birthday = models.DateField()

说明:

  • 1、EmailField 数据类型是邮箱格式,底层继承 CharField,进行了封装,相当于 MySQL 中的 varchar。
  • 2、Django1.1 版本不需要联级删除:on_delete=models.CASCADE,Django2.2 需要。
  • 3、一般不需要设置联级更新.
  • 4、外键在一对多的多中设置:models.ForeignKey("关联类名", on_delete=models.CASCADE)。
  • 5、OneToOneField = ForeignKey(...,unique=True)设置一对一。
  • 6、若有模型类存在外键,创建数据时,要先创建外键关联的模型类的数据,不然创建包含外键的模型类的数据时,外键的关联模型类的数据会找不到。

表结构

书籍表 Book:title 、 price 、 pub_date 、 publish(外键,多对一) 、 authors(多对多)

出版社表 Publish:name 、 city 、 email

作者表 Author:name 、 age 、 au_detail(一对一)

作者详情表 AuthorDetail:gender 、 tel 、 addr 、 birthday

以下是表格关联说明:

三. 插入数据

我们在 MySQL 中执行以下 SQL 插入操作:

insert into app01_publish(name,city,email) values ("华山出版社", "华山", "hs@163.com"), ("明教出版社", "黑木崖", "mj@163.com")
 
# 先插入 authordetail 表中多数据
insert into app01_authordetail(gender,tel,addr,birthday) values (1,13432335433,"华山","1994-5-23"), (1,13943454554,"黑木崖","1961-8-13"), (0,13878934322,"黑木崖","1996-5-20") 

# 再将数据插入 author,这样 author 才能找到 authordetail 
insert into app01_author(name,age,au_detail_id) values ("令狐冲",25,1), ("任我行",58,2), ("任盈盈",23,3)

四. ORM - 添加数据

4.1. 一对多(外键 ForeignKey)

方式一: 传对象的形式,返回值的数据类型是对象,书籍对象。

步骤:

  • a. 获取出版社对象
  • b. 给书籍的出版社属性 pulish 传出版社对象
def add_book(request):
    #  获取出版社对象
    pub_obj = models.Publish.objects.filter(pk=1).first()
    #  给书籍的出版社属性publish传出版社对象
    book = models.Book.objects.create(title="蜡笔小流", price=200, pub_date="2024-10-10", publish=pub_obj)
    print(book, type(book))
    return HttpResponse(book)

方式二: 传对象 id 的形式(由于传过来的数据一般是 id,所以传对象 id 是常用的)。

一对多中,设置外键属性的类(多的表)中,MySQL 中显示的字段名是:外键属性名_id

返回值的数据类型是对象,书籍对象。

步骤:

  • a. 获取出版社对象的 id
  • b. 给书籍的关联出版社字段 pulish_id 传出版社对象的 id
def add_book(request):
    #  获取出版社对象
    pub_obj = models.Publish.objects.filter(pk=1).first()
    #  获取出版社对象的id
    pk = pub_obj.pk
    #  给书籍的关联出版社字段 publish_id 传出版社对象的id
    book = models.Book.objects.create(title="冲灵剑法", price=100, pub_date="2024-04-03", publish_id=pk)
    print(book, type(book))
    return HttpResponse(book)

4.2. 多对多(ManyToManyField):在第三张关系表中新增数据

方式一: 传对象形式,无返回值。

步骤:

  • a. 获取作者对象
  • b. 获取书籍对象
  • c. 给书籍对象的 authors 属性用 add 方法传作者对象
def add_book(request):
    #  获取作者对象
    chong = models.Author.objects.filter(name="令狐冲").first()
    ying = models.Author.objects.filter(name="任盈盈").first()
    #  获取书籍对象
    book = models.Book.objects.filter(title="蜡笔小流").first()
    #  给书籍对象的 authors 属性用 add 方法传作者对象
    book.authors.add(chong, ying)
    return HttpResponse(book)

方式二: 传对象id形式,无返回值。

步骤:

  • a. 获取作者对象的 id
  • b. 获取书籍对象
  • c. 给书籍对象的 authors 属性用 add 方法传作者对象的 id
def add_book(request):
    #  获取作者对象
    chong = models.Author.objects.filter(name="令狐冲").first()
    #  获取作者对象的id
    pk = chong.pk
    #  获取书籍对象
    book = models.Book.objects.filter(title="冲灵剑法").first()
    #  给书籍对象的 authors 属性用 add 方法传作者对象的id
    book.authors.add(pk)

4.3. 关联管理器(对象调用)

前提:

  • 多对多(双向均有关联管理器)
  • 一对多(只有多的那个类的对象有关联管理器,即反向才有)

语法格式:

正向:属性名
反向:小写类名加 _set

注意:一对多只能反向

常用方法:

add():用于多对多,把指定的模型对象添加到关联对象集(关系表)中。

注意:add() 在一对多(即外键)中,只能传对象( *QuerySet数据类型),不能传 id(*[id表])。

*[ ] 的使用:

# 方式一:传对象

book_obj = models.Book.objects.get(id=10)
author_list = models.Author.objects.filter(id__gt=2)
book_obj.authors.add(*author_list)  # 将 id 大于2的作者对象添加到这本书的作者集合中
# 方式二:传对象 id
book_obj.authors.add(*[1,3]) # 将 id=1 和 id=3 的作者对象添加到这本书的作者集合中
return HttpResponse("ok")

反向:小写表名_set

ying = models.Author.objects.filter(name="任盈盈").first()
book = models.Book.objects.filter(title="冲灵剑法").first()
ying.book_set.add(book)
return HttpResponse("ok")

create():创建一个新的对象,并同时将它添加到关联对象集之中。

返回新创建的对象。

pub = models.Publish.objects.filter(name="明教出版社").first()
wo = models.Author.objects.filter(name="任我行").first()
book = wo.book_set.create(title="吸星大法", price=300, pub_date="2024-9-19", publish=pub)
print(book, type(book))
return HttpResponse("ok")

remove():从关联对象集中移除执行的模型对象。

对于 ForeignKey 对象,这个方法仅在 null=True(可以为空)时存在,无返回值。

author_obj =models.Author.objects.get(id=1)
book_obj = models.Book.objects.get(id=11)
author_obj.book_set.remove(book_obj)
return HttpResponse("ok")

clear():从关联对象集中移除一切对象,删除关联,不会删除对象。

对于 ForeignKey 对象,这个方法仅在 null=True(可以为空)时存在。

无返回值。

#  清空独孤九剑关联的所有作者
book = models.Book.objects.filter(title="蜡笔小流").first()
book.authors.clear()

五. ORM 查询

基于对象的跨表查询。

正向:属性名称
反向:小写类名_set

5.1. 一对多

查询主键为 1 的书籍的出版社所在的城市(正向)。

book = models.Book.objects.filter(pk=10).first()
res = book.publish.city
print(res, type(res))
return HttpResponse("ok")

查询明教出版社出版的书籍名(反向)。

反向:对象.小写类名_set(pub.book_set) 可以跳转到关联的表(书籍表)。

pub.book_set.all():取出书籍表的所有书籍对象,在一个 QuerySet 里,遍历取出一个个书籍对象。

pub = models.Publish.objects.filter(name="明教出版社").first()
res = pub.book_set.all()
for i in res:
    print(i.title)
return HttpResponse("ok")

5.2. 一对一

查询令狐冲的电话(正向)

正向:对象.属性 (author.au_detail) 可以跳转到关联的表(作者详情表)

author = models.Author.objects.filter(name="令狐冲").first()
res = author.au_detail.tel
print(res, type(res))
return HttpResponse("ok")

查询所有住址在黑木崖的作者的姓名(反向)。

一对一的反向,用 对象.小写类名 即可,不用加 _set。

反向:对象.小写类名(addr.author)可以跳转到关联的表(作者表)。

addr = models.AuthorDetail.objects.filter(addr="黑木崖").first()
res = addr.author.name
print(res, type(res))
return HttpResponse("ok")

5.3. 多对多

蜡笔小流所有作者的名字以及手机号(正向)。

正向:对象.属性(book.authors)可以跳转到关联的表(作者表)。

作者表里没有作者电话,因此再次通过对象.属性(i.au_detail)跳转到关联的表(作者详情表)。
book = models.Book.objects.filter(title="蜡笔小流").first()
res = book.authors.all()
for i in res:
    print(i.name, i.au_detail.tel)
return HttpResponse("ok")

查询任我行出过的所有书籍的名字(反向)。

author = models.Author.objects.filter(name="任我行").first()
res = author.book_set.all()
for i in res:
    print(i.title)
return HttpResponse("ok")

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

正向:属性名称__跨表的属性名称 反向:小写类名__跨表的属性名称

6.1. 一对多

查询蜡笔出版社出版过的所有书籍的名字与价格。

res = models.Book.objects.filter(publish__name="蜡笔出版社").values_list("title", "price")

反向:通过 小写类名__跨表的属性名称(book__title,book__price) 跨表获取数据。

res = models.Publish.objects.filter(name="蜡笔出版社").values_list("book__title","book__price")
return HttpResponse("ok")

6.2. 多对多

查询任我行出过的所有书籍的名字。

正向:通过 属性名称__跨表的属性名称(authors__name) 跨表获取数据:

res = models.Book.objects.filter(authors__name="任我行").values_list("title")

反向:通过 小写类名__跨表的属性名称(book__title) 跨表获取数据:

res = models.Author.objects.filter(name="任我行").values_list("book__title")

6.3. 一对一

查询任我行的手机号。

正向:通过 属性名称__跨表的属性名称(au_detail__tel) 跨表获取数据。

res = models.Author.objects.filter(name="任我行").values_list("au_detail__tel")

反向:通过 小写类名__跨表的属性名称(author__name) 跨表获取数据。

res = models.AuthorDetail.objects.filter(author__name="任我行").values_list("tel")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2093843.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

eNSP-交换机的广播域和冲突域

一、广播域、冲突域 冲突域:一台电脑发送消息,其他电脑不能发送所影响的范围,就是冲突域。 广播域:一台电脑发送广播,所能广播到的范围。 二、举例 1.总线结构 广播域是整个总线的网络范围,冲突域也是整…

uniapp+vue3+setup返回上一页传参

huilderx 版本 list function getId(data) {// console.log(接收到的参数, data)if (data) {buildObj.value JSON.parse(data);} }onShow((options) > {getBuild() })// 暴露方法 defineExpose({getId })detail import { ref, onMounted, onUnmounted } from vue import…

ElasticSearch和Kibana的安全设置以及https设置

👨‍💻本文专栏:ElasticSearch和Kibana的安全设置以及https设置 👨‍💻本文简述:跟着猿灰灰一起学Java! 👨‍💻上一篇文章: 👨‍💻有任…

3D打印透气钢与传统透气钢的差异

透气钢作为一种集金属强度与透气性能于一体的特殊材料,在注塑模具领域扮演着关键角色,通过有效排除模具内困气,显著提升制品成型质量与生产效率。当前,市场上主流的透气钢产品多源自日本、美国,其高昂成本与技术壁垒限…

【国铁采购平台-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 1. 暴力破解密码,造成用户信息泄露 2. 短信盗刷的安全问题,影响业务及导致用户投诉 3. 带来经济损失,尤其是后付费客户,风险巨大,造…

vue项目安装pnpm和无法加载pnpm,已解决

vue3安装pnpm命令: 1.提升依赖安装速度:npm config set registry https://registry.npmjs.org 2.安装pnpm:npm install -g pnpm 3.安装pnpm依赖:pnpm install 4…windows电脑,无法安装pnpm,pnpm install命令&#xff0…

C++基础知识七

1.对象拷贝时编译器优化 现代编译器为了尽快提高程序的效率,不影响正确性的情况下会尽可能减少一些传参和传参过程中可以省略的拷贝 例子: 先调用f()函数,则应该先触发构造函数初始化a,return a时先拷贝a…

机器学习之监督学习(一)线性回归、多项式回归、算法优化[巨详细笔记]

机器学习之监督学习(一)线性回归、多项式回归、算法优化 1.监督学习定义2.监督学习分类2.1回归 regression2.2 分类 classification 3.线性回归 linear regression3.1 单特征线性回归模块一:梯度下降 3.2 多特征线性回归模块二:正…

CohereForAI更新企业级开源模型 c4ai-command-r-08-2024和c4ai-command-r-plus-08-2024

C4AI Command R 08-2024 是一个 350 亿参数高性能生成模型的研究版本。 Command R 08-2024 是一个大型语言模型,采用开放式权重,针对推理、总结和问题解答等各种用例进行了优化。 Command R 08-2024 具备多语言生成功能,曾在 23 种语言上进行…

nginx平滑升级与回滚

华子目录 升级实验环境准备测试内容准备实验要求实验步骤1.解压包2.检测1.26版本的环境3.make编译4.备份之前的nginx启动脚本5.将1.26中的nginx启动脚本覆盖掉1.24中的6.kill -USR2 旧主进程pid7.kill -WINCH 旧主进程pid 实验测试 回滚1.kill -HUP 旧主进程pid2.kill -WINCH 新…

【MySQL】索引性能分析工具详解——>为sql优化(select)做准备

前言 大家好吖,欢迎来到 YY 滴MySQL系列 ,热烈欢迎! 本章主要内容面向接触过C的老铁 主要内容含: 欢迎订阅 YY滴C专栏!更多干货持续更新!以下是传送门! YY的《C》专栏YY的《C11》专栏YY的《Lin…

机械学习—零基础学习日志(概率论总笔记1)

概率论的起源 在历史上有明确记载的最早研究随机性的数学家是帕斯卡和费马。帕斯卡就是最早发明机械计算机的那位数学家,他并不是赌徒,但是他有些赌徒朋友,那些人常常玩一种掷骰子游戏,游戏规则是由玩家连续掷4次骰子&#xff0c…

Java | Leetcode Java题解之第378题有序矩阵中第K小的元素

题目&#xff1a; 题解&#xff1a; class Solution {public int kthSmallest(int[][] matrix, int k) {int n matrix.length;int left matrix[0][0];int right matrix[n - 1][n - 1];while (left < right) {int mid left ((right - left) >> 1);if (check(matr…

Python酷库之旅-第三方库Pandas(113)

目录 一、用法精讲 496、pandas.DataFrame.kurtosis方法 496-1、语法 496-2、参数 496-3、功能 496-4、返回值 496-5、说明 496-6、用法 496-6-1、数据准备 496-6-2、代码示例 496-6-3、结果输出 497、pandas.DataFrame.max方法 497-1、语法 497-2、参数 497-3、…

如何从 SD 卡恢复已删除的文件:分步指南

在 SD 卡上查找已删除的文件可能是一项相当艰巨的任务&#xff0c;尤其是当您认为它们已经消失得无影无踪时。然而&#xff0c;希望还是有的&#xff01;现代技术提供了多种有效的方法来恢复这些文件&#xff0c;无论是照片、文档还是其他类型的数据。使用正确的工具和一点耐心…

【初出江湖】大白话解释集中式、分布式、微服务的区别?

目录标题 什么是集中式&#xff1f;什么是分布式&#xff1f;分布式系统的架构一般构成模块分布式的优点分布式的缺点什么是分布式集群&#xff1f; 什么是微服务&#xff1f;微服务和分布式系统有什么主要区别&#xff1f;微服务架构与分布式系统在开发过程中有何不同&#xf…

嵌入式:Arm v7-M指令集架构中的字节序(大小端)

相关阅读 嵌入式https://blog.csdn.net/weixin_45791458/category_12768532.html?spm1001.2014.3001.5482 本文来源于博主无意之中的一个发现&#xff0c;虽然之前就知道Cortex-M3默认为小端模式&#xff0c;但是偶然发现了一些出乎意料的情况。 首先来看看Arm v7-M指令集架构…

【MarkDown】表格的对齐方法

MarkDown中表格的对齐方法 说明格式化对齐举例 摘要&#xff1a; 1.本文介绍了MarkDown语法中&#xff0c;插入表格后&#xff0c;表格的对齐方法 2.在CSDN写博客时&#xff0c;要经常用的功能&#xff0c;务必掌握这个小技巧 说明 在Markdown中创建表格&#xff0c;基本结构由…

奇偶校验、crc循环冗余检验

数据链路层 链路 从一个结点到相邻结点的一段物理线路&#xff0c;而中间没有任何其他的交换点 数据链路 是指把实现通信协议的硬件和软件加到链路上 帧 在数据链路上传输的数据包&#xff0c;称之为帧 数据链路层是以帧为单位进行传输和处理数据的 数据链路层的三个重…

用Springboot(java程序)访问Salesforce RestAPI(通过JWT认证)

外部系统想访问Salesforce的数据,发Rest请求,必须需要Salesforce的AccessToken。那么为了得到这个AccessToken,Salesforce有几种方式可供选择。 一种就是用户名密码认证方式(之前的文章介绍过通过java代码访问Salesforce),一种就是JWT认证方式。当然还有其他方式,之后有…