【SQLAlChemy】表之间的关系,外键如何使用?

news2025/3/1 11:46:36

表之间的关系

数据库表之间的关系分为三种:

  • 一对一关系(One-to-One):在这种关系中,表A的每一行都与表B的一行关联,反之亦然。例如,每个人都有一个唯一的社保号,每个社保号也只属于一个人。
  • 一对多关系(One-to-Many):在这种关系中,表A的一行可以与表B的多行关联,但表B的每一行只能与表A的一行关联。例如,一位母亲可以有多个孩子,但每个孩子只能有一个生物学上的母亲。
  • 多对多关系(Many-to-Many):在这种关系中,表A的一行可以与表B的多行关联,表B的一行也可以与表A的多行关联。例如,一个学生可以选修多门课程,一门课程也可以被多个学生选修。

在数据库中,这些关系通常通过使用外键(Foreign Key)来建立。

外键

外键(Foreign Key)是一种特殊类型的数据库约束,主要用于创建表之间的链接或关系。

外键是在一个表中创建的,它是另一个表的主键(Primary Key)。这个外键用来指向另一个表的主键,从而建立两个表之间的关系。

外键的主要目的是维护数据的引用完整性。这意味着,如果试图在一个表中插入一行,而这行数据的外键值在相关表中不存在,数据库将不允许这个操作。同样,如果试图删除一个表中的行,而这行数据的主键在其他表中作为外键存在,那么数据库也不会允许这个删除操作,除非先删除或更改引用这个主键的所有外键。

例如,假设有两个表,一个是学生表,一个是课程表。每个学生可以注册多个课程,所以在课程表中,可能会有一个列叫做 "student_id",这个列是学生表的外键。这样,就可以通过学生的 ID 查询他们注册的所有课程,同时也保证了每个课程都有一个注册的学生。

使用 SQLAlchemy 创建外键的步骤:

  1. 定义表格:首先,需要定义数据库表格。每个表格对应一个 SQLAlchemy 类,类中的每个属性对应表格中的一个列。
  2. 设置外键:在定义表格的过程中,可以使用 ForeignKey 函数来设置外键。ForeignKey 函数的参数是想要链接的表格的列名。例如,如果有一个 Order 表,想让它链接到 Customer 表的 id 列,可以这样写: customer_id = Column(Integer, ForeignKey('customer.id'))
  3. 创建关系:在设置了外键之后,还需要在 SQLAlchemy 类中使用 relationship 函数来创建两个表格之间的关系。例如,可以在 Customer 类中添加如下的代码: orders = relationship("Order", backref="customer")。 这段代码表示一个客户可以有多个订单,每个订单都有一个关联的客户。
  4. 创建数据库:最后,需要使用 SQLAlchemy 的 create_all 函数来创建数据库。这个函数会根据定义的 SQLAlchemy 类来创建表格,并设置好所有的外键和关系。

实例

实现学生 StudentLesson 之间的关系表的建立。

python 代码:

Base = declarative_base()


# 定义 Student 表
class Student(Base):
    __tablename__ = 'student'
    id = Column(Integer, primary_key=True)
    name = Column(String(50), nullable=False)
    age = Column(Integer)

    def __repr__(self):
        return "<Student(name='%s', age='%s')>" % (self.name, self.age)


# 定义 Lesson 表
class Lesson(Base):
    __tablename__ = 'lesson'
    id = Column(Integer, primary_key=True)
    name = Column(String(50), nullable=False)
    description = Column(String(100), nullable=False)
    student_id = Column(Integer, ForeignKey('student.id'))

    def __repr__(self):
        return "<Lesson(name='%s', description='%s')>" % (self.name, self.description)


Base.metadata.create_all(engine)

sql语句代码:

create table student
(
    id   int auto_increment
        primary key,
    name varchar(50) not null,
    age  int         null
);

create table lesson
(
    id          int auto_increment
        primary key,
    name        varchar(50)  not null,
    description varchar(100) not null,
    student_id  int          null,
    constraint lesson_ibfk_1
        foreign key (student_id) references student (id)
);

create index student_id
    on lesson (student_id);

表关系图:

测试插入数据:

# 测试插入数据

# Student 数据
stu1 = Student(name='zmz', age=10)
stu2 = Student(name='ypb', age=18)
stu3 = Student(name='gll', age=20)

session.add_all([stu1, stu2, stu3])
session.commit()

# Lesson 数据
l1 = Lesson(name='java', description='this is java', student_id=stu1.id)
l2 = Lesson(name='java', description='this is java', student_id=stu2.id)
l3 = Lesson(name='python', description='this is python', student_id=stu1.id)
session.add_all([l1, l2, l3])
session.commit()

数据库 student 表:

数据库 lesson 表:

外键约束分类

  • RESTRICT:这是默认选项。当尝试删除父表中的数据时,如果子表中存在与之关联的数据,那么这个删除操作将会被阻止。也就是说,只有当没有任何子表行与父表行关联时,才能删除父表中的行。
  • NO ACTION:在 MySQL 中,这个选项的行为与 RESTRICT 选项相同。也就是说,如果子表中存在与父表行关联的行,那么尝试删除父表中的行将会被阻止。
  • CASCADE:这个选项表示级联删除。当你删除父表中的行时,所有在子表中与之关联的行也会被自动删除。这种选项需要谨慎使用,因为它可能会导致大量的数据被删除。
  • SET NULL:当父表中的行被删除时,这个选项会将子表中所有与之关联的行的外键列设置为 NULL。这意味着,子表中的这些行不再与父表中的任何行关联。注意,为了使用这个选项,子表的外键列必须允许 NULL 值。

修改 lesson 表:

# 定义 Lesson 表
class Lesson(Base):
    __tablename__ = 'lesson'
    id = Column(Integer, primary_key=True)
    name = Column(String(50), nullable=False)
    description = Column(String(100), nullable=False)
    student_id = Column(Integer, ForeignKey('student.id', ondelete='CASCADE'), nullable=False)

    def __repr__(self):
        return "<Lesson(name='%s', description='%s')>" % (self.name, self.description)

注意事项

问题:

加入在添加数据时,我们先提交了 student 中的数据,之后在提交了 lesson 中的数据,会造成 lessonstudent_id 为空。

分析:

在 SQLAlchemy 中,当使用 session.add() 方法时,数据并不会立即被写入数据库,而是被添加到了会话的事务队列中。只有当调用 session.commit() 方法时,才会将这些变更写入数据库。在这之前,新创建的 Student 对象的 id 属性是 None,因为它们还没有被分配数据库中的 id

在代码中,首先创建了几个 Student 对象,并使用 session.add_all() 添加到会话中,但是在添加 Lesson 对象之前,没有调用 session.commit()。因此,当试图访问 stu1.id 时,它其实是 None,这就是为什么在插入 Lesson 数据时会出现错误。
为了解决这个问题,需要在添加 Lesson 对象之前,先提交 Student 对象。

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

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

相关文章

深度学习(六)——神经网络的基本骨架:nn.Module的使用

一、torch.nn简介 官网地址&#xff1a; torch.nn — PyTorch 2.0 documentation 1. torch.nn中的函数简介 Containers&#xff1a;神经网络的骨架 Convolution Layers&#xff1a;卷积层 Pooling layers&#xff1a;池化层 Padding Layers&#xff1a;Padding Non-linear …

android 播放视频

播放视频文件 新建一个activity_main.xml文件&#xff0c;文件中放置了3个按钮&#xff0c;分别用于控制视频的播放、暂停和重新播放。另外在按钮的下面又放置了一个VideoView&#xff0c;稍后的视频就将在这里显示。 <LinearLayout xmlns:android"http://schemas.an…

Android Studio新增功能:Device Streaming

今天将Android Studio升级到2023.3.1 Patch2。发现新增了Device Streaming功能。支持远程使用Google的物理设备调试程序。这样可以方便地在真实设备上测试自己的APP。这对于手头没有Google设备的开发者而言&#xff0c;确实方便很多。该功能目前处于测试阶段&#xff0c;在2025…

【机器学习300问】117、序列模型中的符号表示方法?以命名实体识别(NER)任务为例。

在序列模型中&#xff0c;特别是在命名实体识别(NER)任务中&#xff0c;我们通常会用一系列符号来表示输入序列、目标标签以及模型的结构和操作。本文列出一些常见的符号表示方法&#xff0c;结合NER任务进行解释。 一、什么是命名实体识别任务&#xff1f; &#xff08;1&am…

06 SpringBoot 配置文件详解-application.yaml

Spring Boot 提供了大量的自动配置&#xff0c;极大地简化了spring 应用的开发过程&#xff0c;当用户创建了一个 Spring Boot 项目后&#xff0c;即使不进行任何配置&#xff0c;该项目也能顺利的运行起来。当然&#xff0c;用户也可以根据自身的需要使用配置文件修改 Spring …

L50--- 104. 二叉树的最大深度(深搜)---Java版

1.题目描述 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 2.思路 这个二叉树的结构如下&#xff1a; 根节点 1 左子节点 2 右子节点 3 左子节点 4 计算过程 从根节点 1 开始计算&#xff1a; 计算左子树的最大深度&#xff1a; 根节点 2&#xf…

QTcreator编译器路径错误,no valid kit found

重装系统后&#xff0c;整个QT的应用换了一个盘&#xff0c;但是创建QT工程时默认的编译器路径还是以前的路径且无法修改&#xff0c;创建工程时&#xff0c;出现no valid kit found 可见在option下的编译器相关路径是在E盘且无法更改 进入现在的QT盘进行文件的修改 F:\QT\Too…

UnityAPI学习之协程原理与作用

协程的原理与作用 Unity 协程(Coroutine)原理与用法详解_unity coroutine-CSDN博客 using System.Collections; using System.Collections.Generic; using UnityEngine;public class NO14_coroutine : MonoBehaviour {Animator animator;// Start is called before the first…

深入掌握SystemVerilog验证:《SystemVerilog验证 测试平台编写指南》(可下载)

在数字设计的世界中&#xff0c;验证是确保硬件设计满足预期功能和性能要求的关键步骤。SystemVerilog作为一种先进的硬件描述语言&#xff0c;以其强大的验证特性&#xff0c;成为了设计和验证工程师的首选工具。 1. SystemVerilog验证的重要性 在数字设计流程中&#xff0c…

javaWeb项目-ssm+vue在线购物系统功能介绍

本项目源码&#xff1a;java-ssmvue在线购物系统的设计与实现源码说明文档资料资源-CSDN文库 项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;sprin…

[Nacos]No spring.config.import property has been defined

在学习 Spring Cloud Alibaba &#xff0c;Nacos组件&#xff0c;创建一个cloudalibaba-config-nacos-client&#xff0c;加载多配置集时遇到问题 配置了 bootstrap.yml 后启动项目报错&#xff1a; 是因为在springcloud 2020.0.2版本中把bootstrap的相关依赖从spring-cloud-s…

Python 中国象棋游戏【含Python源码 MX_011期】

简介&#xff1a; 中国象棋是一种古老而深受喜爱的策略棋类游戏&#xff0c;也被称为中国的国粹之一。它在中国有着悠久的历史&#xff0c;起源可以追溯到几个世纪以前。Python 中国象棋游戏是一个用Python编程语言编写的软件程序&#xff0c;旨在模拟和提供中国象棋的游戏体验…

一键获取CPU详情:Python最强查询工具实战教程

要在 Python 中查询 CPU 信息,可以使用多个强大的工具和库.以下是一些最常用和强大的库,可以帮助你获取详细的 CPU 信息&#xff1a; 1.psutil 2.cpuinfo 3.platform 4.os 1. 使用 psutil 库 psutil 是一个跨平台库,提供了获取系统和进程信息的便捷方法.它不仅可以获取 C…

I/O Stream设计实验

实验要求和目的 深入理解java输入输出流相关类的基本用法&#xff0c;并且可以掌握Java程序的编写和调试。 实验环境 Java语言&#xff0c;PC或android平台 实验具体内容 设计和编写以下程序&#xff1a; 程序1&#xff1a; 从键盘读入多行字符串&#xff08;英文&#xf…

生产运作管理--第六版陈荣秋

第一章&#xff1a; 生产运作的分类有哪些&#xff1f; 答&#xff1a;可以分为两大类&#xff1a; 产品生产: 产品生产是通过物理或者化学作用将有形输入转化为有形输出的过程。 按照工艺过程的特点&#xff0c;可以分为&#xff1a; 连续性生产&#xff1a;物料均匀、连续的按…

右值引用和移动语义

什么是左值&#xff1f;什么是右值&#xff1f; 通俗来讲&#xff0c;可以出现在赋值语句左侧的&#xff0c;为左值&#xff1b;只能出现在赋值语句右侧的&#xff0c;为右值。 左值与右值的本质区别在于&#xff1a;左值能取地址&#xff0c;但右值不能。 本文主要通过三个场景…

Commons-io工具包与Hutool工具包

Commons-io Commons-io是apache开源基金组织提供的一组有关IO操作的开源工具包 作用:提高I0流的开发效率。 FileUtils类(文件/文件夹相关) static void copyFile(File srcFile,File destFile) 复制文件 static void copyDirectory(File srcDir,File destDir) 复…

你的职业规划就是面向贫穷的规划

如果你觉得作者的文章还有点用,请记得点赞 + 关注 说一个扎心的事实,就是我们绝大多数人的职业规划基本上都是错误的,都是面向贫穷的规划。 因为绝大多数人的职业规划都是打工人的职业规划,这种规划除了很少部分人最终能成为企业高管,实现层级跃迁外,绝大多数人在大多数…

递归解析 LXML 树并避免重复进入某个节点

1、问题背景 我们在使用 LXML 库解析 MathML 表达式时&#xff0c;可能会遇到这样一个问题&#xff1a;在递归解析过程中&#xff0c;我们可能会重复进入同一个节点&#xff0c;导致解析结果不正确。例如&#xff0c;我们希望将以下 MathML 表达式解析为 Python 表达式&#x…

DJ-122A电压继电器 柜内安装 电磁式继电器 约瑟JOSEF

系列型号&#xff1a; DJ-100A/Q系列电压继电器 DJ-111A/Q电压继电器; DJ-112A/Q电压继电器; DJ-121A/Q电压继电器; DJ-122A/Q电压继电器; DJ-131A/Q电压继电器; DJ-132A/Q电压继电器; DJ-131A/Q160CN电压继电器; DJ-131A/Q160C电压继电器; ​ 概述 DJ-100A/Q系列电…