【Flask框架】——26 ORM关联关系

news2024/11/24 0:34:24

在这里插入图片描述

在这里插入图片描述


1、表的外键关联

使用SQLAlchemy创建外键非常简单。在从表中增加一个字段,指定这个字段外键的是哪个表的哪个字段就可以了。从表中外键的字段,必须和主表的主键字段类型保持一致。

这种关联只关注数据表之间的外键关联,不考虑Python对象之间的关联关系.

# 部门和员工之间,是一种典型的一(主)对多(从)
class Department(Base):
    __tablename__ = 't_dept'
    dept_no = Column(Integer, primary_key=True)
    d_name = Column(String(255))  # 部门名字
    city = Column(String(50))


# 员工表
class Employee(Base):
    __tablename__ = 't_emp'
    emp_no = Column(Integer, primary_key=True)
    emp_name = Column(String(50))
    job = Column(String(50))
    hire_time = Column(DATE)  # 入职时间
    sal = Column(DECIMAL(10, 2))  # 薪资,连两位小数共十位
    dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='CASCADE'))

外键的删除选项

  1. RESTRICT:若子表中有父表对应的关联数据,删除父表对应数据,会阻止删除。默认项
  2. NO ACTION:在MySQL中,同RESTRICT
  3. CASCADE:级联删除。
  4. SET NULL:父表对应数据被删除,子表对应数据项会设置为NULL。
from datetime import date
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

engine = create_engine('mysql+pymysql://root:root@localhost:3306/flask_db?charset=utf8mb4', echo=True)

Base = declarative_base(engine)


# 部门和员工之间,是一种典型的一(主)对多(从)
class Department(Base):
    __tablename__ = 't_dept'
    dept_no = Column(Integer, primary_key=True)
    d_name = Column(String(255))  # 部门名字
    city = Column(String(50))


# 员工表
class Employee(Base):
    __tablename__ = 't_emp'
    emp_no = Column(Integer, primary_key=True)
    emp_name = Column(String(50))  # 员工名字
    job = Column(String(50))
    hire_time = Column(DATE)  # 入职时间
    sal = Column(DECIMAL(10, 2))  # 薪资,连两位小数共十位
    # dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='NO ACTION'))
    # dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='CASCADE'))  # 级联删除
    # dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='RESTRICT'))  #
    dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='SET NULL'))  #


Base.metadata.drop_all()
Base.metadata.create_all()


d1 = Department(d_name='人事部', city='昆明')
e1 = Employee(emp_name='张三', job='经理', hire_time=date(2022, 12, 22), sal=6666.50, dept_no=1)

# 创建session对象
session = sessionmaker(engine)()


def add():
    session.add(d1)
    session.add(e1)
    session.commit()


add()

# 删除
dept = session.query(Department).first()
session.delete(dept)
session.commit()

2、ORM中的一对多/多对一

mysql表级别的外键,还不够爽,必须拿到一个表的外键,然后通过这个外键再去另外一张表中查找,这样太麻烦了。

SQLAlchemy提供了一个 relationship ,这个类可以定义属性,以后在访问相关联的表的时候就直接可以通过属性访问的方式就可以访问得到了。另外,可以通过 backref 来指定反向访问的属性名称。部门和员工之间的关系是一个“一对多”的关系。

# -*- coding: utf-8 -*-

"""
@file: 数据库表的外键关联.py
@author: 北极的三哈
@time: 2022/12/26 14:56
@email:flymeawei@163.com
@software: PyCharm2022.3
"""
from datetime import date
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship

engine = create_engine('mysql+pymysql://root:root@localhost:3306/flask_db?charset=utf8mb4', echo=True)

Base = declarative_base(engine)


# 部门和员工之间,是一种典型的一(主)对多(从)
class Dep(Base):
    __tablename__ = 't_dept'
    dept_no = Column(Integer, primary_key=True)
    d_name = Column(String(255))  # 部门名字
    city = Column(String(50))
    # 代表当前部门下所有员工的列表, 这种写法不是最优的, 最优的写法只要在其中一个对象中关联
    emp = relationship("Emp")  # 参数必须是另外一个相关联的类名

    def __str__(self):
        return 'DEP:<部门名字:{}, 城市:{}>'.format(self.d_name, self.city)


# 员工表
class Emp(Base):
    __tablename__ = 't_emp'
    emp_no = Column(Integer, primary_key=True)
    emp_name = Column(String(50))  # 员工名字
    job = Column(String(50))
    hire_time = Column(DATE)  # 入职时间
    sal = Column(DECIMAL(10, 2))  # 薪资,连两位小数共十位
    # dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='NO ACTION'))
    # dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='CASCADE'))  # 级联删除
    dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='RESTRICT'))  #
    # dept_no = Column(Integer, ForeignKey('t_dept.dept_no', ondelete='SET NULL'))  #
    dept = relationship("Dep")

    def __str__(self):
        return "EMP:<员工编号:{}, 员工姓名:{}>".format(self.emp_no, self.emp_name)


Base.metadata.drop_all()
Base.metadata.create_all()


d1 = Dep(d_name='人事部', city='上海')
d2 = Dep(d_name='销售部', city='上海')
e1 = Emp(emp_name='张三', job='经理', hire_time=date(2022, 12, 22), sal=6666.50, dept_no=1)
e2 = Emp(emp_name='李四', job='经理', hire_time=date(2022, 12, 22), sal=6666.50, dept_no=1)
e3 = Emp(emp_name='王二', job='经理', hire_time=date(2022, 12, 22), sal=6666.50, dept_no=2)
e4 = Emp(emp_name='麻子', job='经理', hire_time=date(2022, 12, 22), sal=6666.50, dept_no=2)

# 创建session对象
session = sessionmaker(engine)()


def add():
    session.add(d1)
    session.add(d2)
    session.add_all([e1, e2, e3, e4])
    session.commit()


add()

# 查询一个部门,关联到部门的员工
d = session.query(Dep).first()
for e in d.emp:
    print(e)

e = session.query(Emp).filter(Emp.emp_no == 4).first()
print(e)
print(e.dept)

在这里插入图片描述


3、ORM中的一对一

在sqlalchemy中,如果想要将两个模型映射成一对一的关系,那么应该在父模型中,指定引用的时候,要传递一个 uselist=False 这个参数进去。就是告诉父模型,以后引用这个从模型的时候,不再是一个列表了,而是一个
对象了。

方法一:参照一对多关联,加上uselist

uselist=False加在没有外键的对象中,其他和前面的一对多关联是一样的。

class Person(Base):
    __tablename__ = 't_person'
    # 在这个ORM模型中创建一些属性,来跟表中的字段进行 一一 映射。
    # 这些属性必须是sqlalchemy给我们提供好的数据类型
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(255))
    age = Column(Integer)
    address = Column(String(255))
    country = Column(String(50))
    # 人对应的身份证
    idcard = relationship('IDcard', uselist=False)


# 员工表
class IDcard(Base):
    __tablename__ = 't_emp'
    card_number = Column(String(18), primary_key=True)
    p_id = Column(Integer, ForeignKey('t_person.id'))  # 外键
    # 该身份证对应的人
    person = relationship('Person')

方法二:在主表中不需要维护关联关系(不用加关联属性),只要在从表对象中加上关联属性,并且加backref

class Person(Base):
    __tablename__ = 't_person'
    # 在这个ORM模型中创建一些属性,来跟表中的字段进行 一一 映射。
    # 这些属性必须是sqlalchemy给我们提供好的数据类型
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(255))
    age = Column(Integer)
    address = Column(String(255))
    country = Column(String(50))
    # 人对应的身份证
    # idcard = relationship('IDcard', uselist=False)  # 不是一个列表

    def __str__(self):
        return "Person[id:{}, name:{}, age:{}]".format(self.id, self.name, self.age)


# 身份证号
class IDcard(Base):
    __tablename__ = 't_idcard'
    card_number = Column(String(18), primary_key=True)
    p_id = Column(Integer, ForeignKey('t_person.id'))  # 外键
    # 该身份证对应的人
    person = relationship('Person', backref=backref('idcard', uselist=False))

4、ORM中的多对多

  1. 多对多的关系需要通过一张中间表来绑定他们之间的关系。

  2. 先把两个需要做多对多的模型定义出来

  3. 使用Table定义一个中间表,中间表一般就是包含两个模型的外键字段就可以了,并且让他们两个来作为一个“复合主键”。

  4. 在两个需要做多对多的模型中随便选择一个模型,定义一个relationship属性,来绑定三者之间的关系,在使用relationship的时候,需要传入一个secondary=中间表对象名。

# 学生和课程之间多对多关系
# 1.定义中间表
temp_tab = Table(
    't_temp_tab',
    Base.metadata,
    # 3.定义中间表联合主键
    Column('s_id', Integer, ForeignKey('t_student.id'), primary_key=True),
    Column('c_id', Integer, ForeignKey('t_course.id'), primary_key=True)
)


# 2.创建多对多模型
# 学生表
class Student(Base):
    __tablename__ = 't_student'
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50))
    age = Column(Integer)

    # 4.定义relationship属性
    course_list = relationship('Course', backref='student_list', secondary=temp_tab)

    def __repr__(self):
        return "Student:name=%s" % self.name


# 课程表
class Course(Base):
    __tablename__ = 't_course'
    id = Column(Integer, primary_key=True, autoincrement=True)
    c_name = Column(String(50))  # 课程名字

    def __repr__(self):
        return "Course:c_name=%s" % self.c_name


# Base.metadata.drop_all()
# Base.metadata.create_all()

# 创建session对象
session = sessionmaker(engine)()


def save():
    s1 = Student(name='张三', age=22)
    s2 = Student(name='李四', age=22)

    c1 = Course(c_name='Python')
    c2 = Course(c_name='MySQL')

    s1.course_list.append(c1)
    s1.course_list.append(c2)
    s2.course_list.append(c1)
    s2.course_list.append(c2)

    session.add(s1)
    session.add(s2)

    session.commit()


# save()


def queryDate():
    s1 = session.query(Student).first()
    print(s1)
    print(s1.course_list)


queryDate()

在这里插入图片描述


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

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

相关文章

ORB-SLAM3代码和算法学习—双目和单目初始化

0总述 ORB-SLAM3算法中视觉的初始化依旧放在tracking线程中&#xff0c;因此在tracking中没有为imu模式设置单独的初始化函数&#xff0c;而IMU的初始化是在localMapping中实现的。 很有用的参考链接&#xff1a;https://cloud.tencent.com/developer/article/1761043 1双目…

【高阶数据结构】搜索二叉树

&#x1f308;欢迎来到数据结构专栏~~搜索二叉树 (꒪ꇴ꒪(꒪ꇴ꒪ )&#x1f423;,我是Scort目前状态&#xff1a;大三非科班啃C中&#x1f30d;博客主页&#xff1a;张小姐的猫~江湖背景快上车&#x1f698;&#xff0c;握好方向盘跟我有一起打天下嘞&#xff01;送给自己的一句…

Word控件Spire.Doc 【评论】教程(2):在 C#、VB.NET 中删除和替换 Word 文档中的注释

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

130页5万字某市档案馆数字档案馆建设方案

【版权声明】本资料来源网络&#xff0c;仅用于行业知识分享&#xff0c;供个人学习参考&#xff0c;请勿商用。【侵删致歉】如有侵权请联系小编&#xff0c;将在收到信息后第一时间进行删除&#xff01; 完整资料领取见文末&#xff0c;部分资料内容&#xff1a; 国家档案局证…

MySQL主从搭建

MySQL主从搭建一 主从配置原理二 搭建步骤&#xff08;基于两个docker容器&#xff09;三 django实现读写分离3.1 配置数据库3.2 models中创建表3.3 数据库迁移3.4 指定要使用的数据库四 Pycharm远程连接服务器进行代码的运行与调试五 Pycharm远程链接docker开发5.1 操作 docke…

SSM图书管理系统(增强版,附源码)

前篇引入&#xff08;新人必看&#xff09;&#xff1a;SSM图书管理系统&#xff08;原版&#xff09; 之前给大家分享过SSM图书管理系统项目的源码&#xff0c;热度较高&#xff0c;但我也发现功能并不是很全面&#xff0c;所以这次对系统进行了功能增强&#xff0c;以下是系…

新手入门搭建一个spring boot项目

1. 打开Idea,新建一个maven项目&#xff0c;详细情况见下图&#xff0c;&#xff08;idea版本2021.1.2&#xff09; 2.查看新建项目的maven包是否存在&#xff0c; 注意&#xff1a;maven包需要自己去下载&#xff0c;注意要下载与版本对应匹配的包 3.导入spring boot 相关的依…

springboot 连接不上 redis 的三种解决方案!

针对于springboot 连接不上 redis 这种情况&#xff0c;首先&#xff0c;我们最简单直接的方法就是需要确认Redis是否已经正常启动&#xff08;验证方法&#xff1a;如果安装在Linux下的话可以使用ps-ef|grep redis来进行确认是否开启&#xff09; 如果未开启&#xff0c;我们可…

STL-string的接口使用及模拟实现

文章目录string类的介绍string类的常用接口介绍 构造相关 无参构造字符串构造拷贝构造 容量相关的接口 sizereserveresizecapacityemptyclear 数据访问及遍历相关的接口 operator[]begin endrbegin rend 修改数据相关的接口 push_backoperatorinserterasec_strfind npossubs…

Redis搭建主从集群

搭建集群 建集群的第一件事情我们需要一些运行在 集群模式的Redis实例。这意味这集群并不是由一些普通的Redis实例组成的&#xff0c;集群模式需要通过配置启用&#xff0c;开启集群模式后的Redis实例便可以使用集群特有的命令和特性了。 下面是一个最少选项的集群的配置文件…

@Builder注解在子类中使用遇到的问题

场景 在项目开发中&#xff0c;需要基于某个类进行一些字段的拓展&#xff0c;那么自然而然想到的做法是extends该类。而两个类都需要使用Builder进行构造。代码如下&#xff1a; Data Builder AllArgsConstructor NoArgsConstructor public class EmployeeDto {private Stri…

详解 Vue3 中如何使用 Proxy 来实现响应式的技术~

详解 Vue3 中如何使用 Proxy 来实现响应式的技术~写在前面剖析 Vue2 中是如何实现响应式的Vue2 的响应式存在什么问题&#xff1f;Vue3 响应式一、ref 函数二、reactive 函数reactive 响应式原理 - ProxyVue3 中的响应式解决了 Vue2 中存在的问题写在前面 Vue3 中的响应式原理…

C++:STL:常见容器:stack,queue, list

一&#xff1a;stack容器 1.1: stack基本概念 概念&#xff1a;stack是一种先进后出 &#xff08;First in last out FILO&#xff09;的数据结构&#xff0c;它只有一个出口。 栈中&#xff1a; 1&#xff1a;只有栈顶的元素才可以被外界使用&#xff0c;因此栈不允许有遍历…

从FrameDebugger看Unity渲染

从FrameDebugger看Unity渲染(一) Unity如何渲染一个3D2D的游戏画面&#xff0c;今天通过FrameDebugger来看下Unity内置渲染管线的渲染策略, 后续再出一些URP渲染管线相关的文章。 对啦&#xff01;这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白&#xff0c…

MyBatis 实现复杂 Sql 查询

resultMap 结果映射 resultMap 元素是 MyBatis 中最重要最强大的元素&#xff0c;之前所写的 sql 语句&#xff0c;返回值都是简单的基本数据类型或者某一个实体类&#xff0c;比如下面这段 sql 返回的就是最简单的 User 类型。 <select id"getUserById" result…

微信HOOK 协议接口 实战开发篇 3.收发文本消息 附详细步骤

前言&#xff1a;本次文章附带详细的HOOK步骤&#xff0c;感兴趣可以尝试一番 使用了之前文章提到的字符搜索法 接收消息 1.OD打开微信&#xff0c;点击e&#xff0c;进入模块列表 2.双击wechatwin模块进入汇编代码页面 3.右键菜单&#xff0c;选择如图示选项 4.进入字符页…

【 uniapp - 黑马优购 | tabBar】如何创建和配置标签栏

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大二在校生&#xff0c;讨厌编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;小新爱学习. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc…

zabbix监控redis修正nodata问题

之前根据网上的资料尝试监控redis&#xff0c;完成后编写了文档。 https://blog.csdn.net/bigwood99/article/details/128404063 这几天观察数据&#xff0c;发现没有数据被采集。 在图标中显示no data。 检查模板中item和graphs设置&#xff0c;发现key中没有使用引号。 …

修复U盘【笔记】

修复U盘【笔记】前言参考修复U盘问题0.芯片精灵查看1.用APTool软件擦除量产信息2.用CBMTool量产U盘结果我的版本最后前言 以下内容源自网络 仅供学习交流使用 参考 总体步骤&芯片精灵下载&#xff1a;https://www.xpwin7.com/jiaocheng/25627.html 资源下载网址来源&am…

组织上线 | 资源共享,协作自如

新功能&#xff5e;&#xff01;期待已久的组织协作上线啦&#xff01; 上线后支持在组织下创建镜像&#xff0c;组织成员可查看、拉取镜像&#xff0c;快速实现镜像资源共享&#xff0c;组织高效协同。 具体怎么操作呢&#xff1f;跟我一起来看一下吧&#xff5e; 创建组织 …