python sqlalchemy(ORM)- 02 表关系

文章目录

  • 创建连接
  • 事务和DBAPI
  • ORM 操作
  • 表关系
  • ORM表示 1v1
  • ORM表示 1vm

创建连接

sqlalchemy应用必须创建一个engine,用于连接数据库;

from sqlalchemy import create_engine
# 创建engine, 懒连接,在ORM中由Session管理
engine = create_engine("sqlite+pysqlite:///:memory:", echo=True, future=True)
# echo 表示sqlalchemy的日志 输出到控制台
# future,表示使用 sqlalchemy2.0 风格的接口
# 连接sqlite (内存)数据库,使用pysqlite DB API,即sqlite3
# 内存数据库,不用创建数据库文件,也不用连接其他的数据库服务器

# 真实创建连接(并开启事务)
conn = engine.connect() # 建议使用python的上下文管理器操作
cursor = conn.exec_driver_sql("select * from stu;")
cursor.fetchall()

conn.commit()/rollback()

 

事务和DBAPI

  1. engine.connect() 创建连接,并开启事务;
# 上下文管理器
with engine.connect() as conn:
	# 开启事务
    conn.exec_driver_sql("create table jack(id int, name varchar(20))")
    conn.exec_driver_sql("insert into jack values(1, 'jack1')")
    conn.exec_driver_sql("insert into jack values(2, 'jack2')")
    # 提交事务
    conn.commit()

# with作用域结束时,若未提交事务,则回滚(engine.connect())
  1. 直接调用conn.execute() 执行text(sql)
    conn.exec_driver_sql() 执行sql
from sqlalchemy import text

# 真实连接
with engine.connect() as conn:
	# sql 语句包裹在 text
	conn.execute(text("CREATE TABLE some_table (x int, y int)"))
	conn.execute(
		text("INSERT INTO some_table (x, y) VALUES (:x, :y)"),
		[{"x": 1, "y": 1}, {"x": 2, "y": 4}],
		)
	
	# 所有的操作 在事务内部(with作用域)
	conn.commit()
  1. engine.begin() 开启事务,并自动提交事务
with engine.begin() as conn:
	conn.exec_driver_sql("create table user(id int, name varchar(30))")

# with作用域结束,自动提交事务
  1. conn.execute()执行文本sql,实现增删改查.
     
 with engine.connect() as conn: # 创建连接,开启事务
 	conn.execute(text("create table if not exists laufing(id int, name varchar(40))"))
    conn.execute(text("insert into laufing values (1, 'jack')"))
    # 查询返回CursorResult对象
    result = conn.execute(text("select * from laufing"))
    print("result:", result, type(result))

	# 获取结果
	print("data:", result.fetchone()) # data: (1, 'jack')
	print("data:", result.fetchall()) # data: [(1, 'jack')]
	# 遍历获取
	for row in result:  # 只能遍历一次  result.mappings() 每行转为字典
		# row is Row obj,也是命名的元组,所以可以像元组一样遍历或者取值
		print(row.id, row.name) # row[0], row[1]

	# 条件查询 :字段名 占位符  参数化的sql   --与原生sql ? 占位符类似
	# 查询 y > 2 的所有数据
	result = conn.execute(text("SELECT x, y FROM some_table WHERE y > :y"), {"y": 2})
	
	# 向laufing表中插入多条数据(参数化)
	conn.execute(text("insert into laufing values (:id, :name)"), [{"id": 2, "name":"lucy"}, {"id": 3, "name": "lili"}])

	# 更新
	conn.execute(text("update laufing set name='xxx' where id > 5"))
	
	# 删除
	conn.execute(text("delete from laufing where id > 5"))

 

ORM 操作

  1. Core sql操作 使用Connection 对象;
  2. ORM 与 数据库 交互,使用Session对象,底层依赖Connection对象触发sql;
  3. 两者的底层均为Engine对象;
  4. ORM 将类 映射为表;类属性映射为表字段;类对象映射为表记录;通过对实例对象的操作,实现数据库的增删改查。

在这里插入图片描述

  1. session的使用
from sqlalchemy import text
from sqlalchemy.orm import Session, sessionmaker

# 上下文管理器
with Session(engine) as session:  # 开启会话,并创建事务
	# 每次执行sql时,从engine 获取一个新的Connection对象
	session.execute(text(sql))
	# 提交事务
	session.commit()
# with作用域结束 则关闭会话session.close()

# 或者
S = sessionmaker(engine) # 返回一个类
session = S()
session.execute(text(sql))
session.commit()  # 写入数据时, 提交事务;查询则不用
session.close()
# 上下文管理器
with Session.begin() as session:  # Session类调用begin()
    session.add(some_object)
    session.add(some_other_object)
# 无异常则提交事务,关闭会话

# 一般使用格式
with Session(engine) as session:
	# 开启事务
    session.begin()
    # 异常捕获
    try:
        session.add(some_object) # 添加一个对象
        session.add(some_other_object)
        session.add_all([obj1, obj2]) # 添加多个对象
    except: # 捕获到异常 则回滚
        session.rollback()
        raise
    else:
        session.commit() #  没有异常则提交

#
# 简便形式
with Session(engine) as session:
    with session.begin(): # 开启事务
        session.add(some_object)
        session.add(some_other_object)
    # inner context calls session.commit()  - 无异常时,自动提交事务
# outer context calls session.close()
# 以上再简写
with Session(engine) as session, session.begin():
    session.add(some_object)
    session.add(some_other_object)
  1. 基于session的查询
# 查询User模型类 的所有字段,(name为ed的)
results = session.query(User).filter_by(name="ed").all() # 返回对象列表

# 查询多个类 
results = session.query(User, Address)
.join("addresses") # 通过User中 与Address 的关系 连接
.filter(User.name=="jack") # 过滤
.all() # [(jack, 北京), (jack, 河南)]  对象元组 列表


# query using orm-columns, also returns tuples
results = session.query(User.name, User.fullname).all()

表关系

  • 1:1,表A 中的一条记录,仅对应表B中的一条记录;表B的一条记录,仅对应表A的一条记录。
  • 1:m,表A中的一条记录,对应表B中的多条记录,表B中的一条记录,仅对应表A的中的一条;(多的一方创建外键)
  • m:n ,表A 中的一条记录,可对应表B中的多条记录;表B的一条记录,也可对应表A的多条记录。

 

ORM表示 1v1

pass

 

ORM表示 1vm

  • 表结构
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 创建模型类
from sqlalchemy import Column, Integer, Float, String, Enum, ForeignKey, VARCHAR
from sqlalchemy.dialects.mysql import VARCHAR
from sqlalchemy.orm import declarative_base, relationship, Session, sessionmaker # sessionmaker返回一个会话类
from sqlalchemy import create_engine

# base class
Base = declarative_base()


# Address
class Address(Base):
	__tablename__ = "address_t"
	id = Column(Integer, primary_key=True)
	# 地址字段, mysql数据库使用VARCHAR类型,其他使用String类型
	title = Column("address", String(50).with_variant(VARCHAR(50, charset="utf8"), "mysql"), nullable=False)
	# 外键
	user_id = Column(Integer, ForeignKey("user_t.id"), nullable=True)
	
	# 关系(非表字段),模型类之间的引用
	# back_populates 双向的 反向引用(通过属性)
	# cascade 级联动作 delete-orphan 表示子表断开引用主表时,删除记录,仅用于1:m 中1的一方
	user = relationship("User", back_populates="addresses")
	def __repr__(self): # 打印对象时的输出
		return f"{self.title}"

# User
class User(Base):
	__tablename__ = "user_t"
	id = Column(Integer, primary_key=True)
	name = Column(String(30), unique=True)
	fullname = Column(String(50))
	# 枚举
	sex = Column(Enum("male", "female", name="sex")) 
	age = Column(Integer)
	role_id = Column(Integer, ForeignKey("role_t.id"), nullable=True)
	
	# 关系
	addresses = relationship("Address", back_populates="user", cascade="all, delete-orphan")
	role = relationship("Role", back_populates="users")
	
	def __repr__(self):
		return f"{self.name}"


# Role
class Role(Base):
	__tablename__ = "role_t"
	id = Column(Integer, primary_key=True)
	name = Column(String(30), unique=True)

	# 关系
	users = relationship("User", back_populates="role")

	def __repr__(self):
		return f"{self.name!r}"


# 创建懒连接
sqlalchemy_database_uri = "postgresql://user:pw@ip:port/dbxx"
engine = create_engine(sqlalchemy_database_uri, echo=True)
# 删除所有的表
Base.metadata.drop_all(engine)
# 创建所有的表
Base.metadata.create_all(engine)
# 创建会话
with Session(engine) as session:
	 jack = User(name="jack", fullname="张三", sex="male", age=34, addresses=[Address(title="北京"), Address(title="河南")])
	 tom = User(name="tom", fullname="李四", sex="female", age=25, addresses=[Address(title="武汉")])
	# 创建角色 
    role = Role(name="老师", users=[jack, tom])
    # 仅仅添加一个****主表记录**** 即可,子表记录 连带添加
    session.add(role)
    session.commit() # 事务的最终提交

在这里插入图片描述
在这里插入图片描述
主表记录插入时,连带子表记录一起插入。
设置user_id时,若对应的数据不在表中,则可以使用关系赋值。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第二证券:AIGC概念活跃,焦点科技、三维通信涨停,万兴科技大涨

AIGC概念24日盘中走势生动,到发稿,万兴科技、三态股份涨超10%,焦点科技、三维通讯、我国科传等涨停,中文在线涨超9%,果麦文明、新国都涨约7%。 消息面上,各大电商途径于10月18-24日先后发动“双11”大促或…

国产CAN总线收发芯片DP1042 兼容替换TJA1042

说明 1 简述 DP1042是一款应用于 CAN 协议控制器和物理总线之间的接口芯片,可应用于卡车、公交、小汽车、工业控制等领域,支持 5Mbps CAN FD 灵活数据速率,具有在总线与 CAN 协议控制器之间进行差分信号传输的能力,完全兼容“ISO…

C指针 --- 进阶

目录 1. 字符指针 1.1. 一般使用 1.2. 另一种使用 2. 指针数组 3. 数组指针 3.1. 数组指针 3.2. 数组名和&数组名 3.3. 数组指针的用处 1. 传递一个数组 2. 传递数组首元素的地址 3. 数组指针处理一维数组 4. 数组指针处理二维数组 4. 数组传参和指针传参 4.1…

全连接层是什么,有什么作用?

大家好啊,我是董董灿。 如果你是搞AI算法的同学,相信你在很多地方都见过全连接层。 无论是处理图片的卷积神经网络(CNN),还是处理文本的自然语言处理(NLP)网络,在网络的结尾做分类…

2023.10.26-SQL测试题

employee表: department表: job表: location表: 题目及答案: -- (1).查询工资大于一万的员工的姓名(first_name与last_name用“.”进行连接)和工资-- select CONCAT(first_name,.,last_name) as 姓名 ,salary -…

Vue(uniapp)父组件方法和子组件方法执行优先顺序

涉及到的知识点:watch监控:先看问题,父组件从后端通过$ajax获取数据,在将父组件将值传输给子组件,使用子组件使用created钩子函数获取数据,按自己的想法应该是父组件先获取后端数据,在传入给子组…

引入个性化标签的协同过滤推荐算法研究_邢瑜航

第3章 引入个性化标签的I-CF推荐算法 3.2.2 相似性度量方法 3.2.3 改进后的算法步骤与流程

Python:一个函数可以被多个装饰器装饰

理解: 规律: 一个函数可以被多个装饰器装饰. wrapper1 wrapper2 def target():print(我是目标)规则和规律 wrapper1 wrapper2 TARGET wrapper2 wrapper1def wrapper1(fn): # fn: wrapper2.innerdef inner(*args, **kwargs):print("这里是wrapper1 …

【RabbitMQ 实战】12 镜像队列

一、镜像队列的概念 RabbitMQ的镜像队列是将消息副本存储在一组节点上,以提高可用性和可靠性。镜像队列将队列中的消息复制到一个或多个其他节点上,并使这些节点上的队列保持同步。当一个节点失败时,其他节点上的队列不受影响,因…

【网络协议】聊聊TCP的三挥四握

上一篇我们说了网络其实是不稳定的,TCP和UDP其实是两个不同的对立者,所以TCP为了保证数据在网络中传输的可靠性,从丢包、乱序、重传、拥塞等场景有自己的一套打法。 TCP格式 源端口和目标端口是不可缺少的,用以区分到达发送给拿…

【每日一题】掷骰子等于目标和的方法数

文章目录 Tag题目来源题目解读解题思路方法一:动态规划 写在最后 Tag 【动态规划】【数组】 题目来源 1155. 掷骰子等于目标和的方法数 题目解读 你手里有 n 个一样的骰子,每个骰子都有 k 个面,分别标号 1 到 n。给定三个整数 n&#xff0…

java异常处理

异常处理分为三类: 检查性异常 用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。 运行时异常 运行时异常是可能被程序员避免的异常&#xf…

2023深耕kotlin,谈谈前景

为什么学习kotlin? Kotlin 早就已经是 Google 官方推荐的开发语言了,而且 Android 新的 Compose 框架只支持 Kotlin ,在 Google 那里,Android开发中 Java 其实已经被淘汰了。Java 和 Kotlin 虽然都属于高级语言,但是 …

LeetCode--2.两数相加

文章目录 1 题目描述2 解题思路2.1 代码实现 1 题目描述 给你两个 非空 的链表, 表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的, 并且每个节点只能存储 一位 数字 请你将两个数相加, 并以相同形式返回一个表示和的链表 你可以假设除了数字 0 之外, 这两个数都…

redis archive github

https://github.com/redis/redis/releases/tag/7.2.2https://github.com/redis/redis/releases/tag/7.2.2

虹科分享 | 买车无忧?AR带来全新体验!

文章来源:虹科数字化与AR 阅读原文:https://mp.weixin.qq.com/s/XsUFCTsiI4bkEMBHcGUT7w 新能源汽车的蓬勃发展,推动着汽车行业加速进行数字化变革。据数据显示,全球新能源汽车销售额持续上升,预计到2025年&#xff0…

VTK OrientationMarker 方向 三维坐标系 相机坐标轴 自定义坐标轴

本文 以 Python 语言开发 我们在做三维软件开发时,经常会用到相机坐标轴,来指示当前空间位置; 坐标轴效果: 相机方向坐标轴 Cube 正方体坐标轴 自定义坐标轴: Code: Axes def main():colors vtkNamedC…

Git总结

Git介绍 一、Git常用命令 添加、提交 git add 将文件从工作区添加到暂存区&#xff0c;表示git开始追踪文件&#xff0c;如果不想让git追踪了&#xff0c;可以使用 git rm --cached <file> 取消文件追踪&#xff0c;仅仅只代表追踪取消&#xff0c;工作区文件还是照…

折磨的Ts

先看下官网 这里的withDefault是给props设置默认值的 由于props传入了个函数在设置默认值的时候不知道怎么设置了 解决办法&#xff1a;直接不设置了。也不写了。

简单了解一下:NodeJS的WebSocket网络编程

NodeJS的webSocket网络编程。 那什么是WebSocket呢&#xff1f;WebSocket是HTML5提供的一种浏览器和服务器进行通信的网络技术。两者之间&#xff0c;只需要做一个握手动作&#xff0c;就可以在浏览器和服务器之间开启一条通道&#xff0c;就可以进行数据相互传输。 实现WebS…