如何使用 Python 和 SQLAlchemy 结合外键映射来获取其他表中的数据

embedded/2025/2/6 11:48:20/

在使用 Python 和 SQLAlchemy 时,结合外键映射可以让你在查询时轻松地获取其他表中的数据。SQLAlchemy 提供了丰富的 ORM(对象关系映射)功能,可以让你通过定义外键关系来查询并获取关联的数据。下面我会演示如何设置外键关系,并通过 SQLAlchemy 查询获取其他表中的数据。

在这里插入图片描述

1、问题背景

在使用 SQLAlchemy 进行对象关系映射时,我们可能需要获取其他表中的数据。例如,我们有一个 Customer 表和一个 Order 表,Customer 表中有 uid、name 和 email 字段,Order 表中有 item_id、item_name 和 customer 字段,customer 字段是 Customer 表的 uid 字段的外键。现在,我们希望从 Order 表中查询订单信息时,同时获取该订单所属客户的姓名和电子邮件地址。

2、解决方案

2.1 双向关系映射

为了实现上述目的,我们需要在 Customer 和 Order 类中分别定义关系属性,使用 relationship() 方法。relationship() 方法的第一个参数指定要映射的类,第二个参数指定反向引用属性。在我们的例子中,Customer 类中的 orders 属性表示该客户的所有订单,Order 类中的 customer 属性表示该订单所属的客户。

python">from sqlalchemy import Table, Column, Integer, String, ForeignKey
from sqlalchemy.orm import mapper, relationship, Session
from sqlalchemy.ext.declarative import declarative_baseBase = declarative_base()class Customer(Base):__tablename__ = 'customers'uid = Column(Integer, primary_key=True)name = Column(String)email = Column(String)def __repr__(self):return str(self)def __str__(self):return "Cust: %s, Name: %s (Email: %s)" %(self.uid, self.name, self.email)class Order(Base):__tablename__ = 'orders'item_id = Column(Integer, primary_key=True)item_name = Column(String)customer_id = Column(Integer, ForeignKey('customers.uid'))def __repr__(self):return str(self)def __str__(self):return "Item ID %s: %s, has been ordered by customer no. %s" %(self.item_id, self.item_name, self.customer)# SQLAlchemy database transmutation
engine = create_engine('sqlite:///:memory:', echo=False)
metadata = MetaData()metadata.create_all(engine)
mapper(Customer, customers_table, properties={'orders': relationship(Order, backref='customer')
})
mapper(Order, orders_table)session = Session(engine)
for order in session.query(Order):print(order, order.customer)

这样,我们就可以通过 Order 对象获取该订单所属客户的信息。

2.2 单向关系映射

如果我们只需要从 Order 表中获取客户信息,而不需要从 Customer 表中获取订单信息,那么我们可以使用单向关系映射。单向关系映射只需要在 Order 类中定义关系属性,不需要在 Customer 类中定义。

python">from sqlalchemy import Table, Column, Integer, String, ForeignKey
from sqlalchemy.orm import mapper, relationship, Session
from sqlalchemy.ext.declarative import declarative_baseBase = declarative_base()class Customer(Base):__tablename__ = 'customers'uid = Column(Integer, primary_key=True)name = Column(String)email = Column(String)def __repr__(self):return str(self)def __str__(self):return "Cust: %s, Name: %s (Email: %s)" %(self.uid, self.name, self.email)class Order(Base):__tablename__ = 'orders'item_id = Column(Integer, primary_key=True)item_name = Column(String)customer_id = Column(Integer, ForeignKey('customers.uid'))def __repr__(self):return str(self)def __str__(self):return "Item ID %s: %s, has been ordered by customer no. %s" %(self.item_id, self.item_name, self.customer)# SQLAlchemy database transmutation
engine = create_engine('sqlite:///:memory:', echo=False)
metadata = MetaData()metadata.create_all(engine)
mapper(Customer, customers_table)
mapper(Order, orders_table, properties={'customer': relationship(Customer)
})session = Session(engine)
for order in session.query(Order):print(order, order.customer)

这样,我们就可以通过 Order 对象获取该订单所属客户的信息,但不能通过 Customer 对象获取该客户的所有订单。

2.3 添加另一个外键

如果我们需要在 Order 表中添加另一个外键,例如 product_id 字段,并且希望获取该订单所属产品的信息,那么我们可以在 Order 类中定义一个新的关系属性,使用 relationship() 方法。relationship() 方法的第一个参数指定要映射的类,第二个参数指定反向引用属性。在我们的例子中,Order 类中的 product 属性表示该订单所属的产品。

python">from sqlalchemy import Table, Column, Integer, String, ForeignKey
from sqlalchemy.orm import mapper, relationship, Session
from sqlalchemy.ext.declarative import declarative_baseBase = declarative_base()class Customer(Base):__tablename__ = 'customers'uid = Column(Integer, primary_key=True)name = Column(String)email = Column(String)def __repr__(self):return str(self)def __str__(self):return "Cust: %s, Name: %s (Email: %s)" %(self.uid, self.name, self.email)class Order(Base):__tablename__ = 'orders'item_id = Column(Integer, primary_key=True)item_name = Column(String)customer_id = Column(Integer, ForeignKey('customers.uid'))product_id = Column(Integer, ForeignKey('products.pid'))def __repr__(self):return str(self)def __str__(self):return "Item ID %s: %s, has been ordered by customer no. %s" %(self.item_id, self.item_name, self.customer)class Product(Base):__tablename__ = 'products'pid = Column(Integer, primary_key=True)product_name = Column(String)def __repr__(self):return str(self)def __str__(self):return "Product ID %s: %s" %(self.pid, self.product_name)# SQLAlchemy database transmutation
engine = create_engine('sqlite:///:memory:', echo=False)
metadata = MetaData()metadata.create_all(engine)
mapper(Customer, customers_table, properties={'orders': relationship(Order, backref='customer')
})
mapper(Order, orders_table, properties={'customer': relationship(Customer),'product': relationship(Product)
})
mapper(Product, products_table)session = Session(engine)
for order in session.query(Order):print(order, order.customer, order.product)

这样,我们就可以通过 Order 对象获取该订单所属客户和产品的信息。

总结

结合外键映射,你可以通过 SQLAlchemy 轻松地获取不同表之间关联的数据。你可以使用:

  1. relationship:设置表之间的关系(如外键),并通过 ORM 获取关联的数据。
  2. 联接查询 (joinedload):通过联接查询加载关联数据,提高查询效率。
  3. 直接访问外键列:直接访问与外键相关的表格数据。

这些方法结合起来,使得 SQLAlchemy 的 ORM 功能非常强大且灵活,能够满足大部分关联查询需求。


http://www.ppmy.cn/embedded/160014.html

相关文章

Electron使用WebAssembly实现CRC-8 MAXIM校验

Electron使用WebAssembly实现CRC-8 MAXIM校验 将C/C语言代码,经由WebAssembly编译为库函数,可以在JS语言环境进行调用。这里介绍在Electron工具环境使用WebAssembly调用CRC-8 MAXIM格式校验的方式。 CRC-8 MAXIM校验函数WebAssembly源文件 C语言实现C…

封装常用控制器

封装常用控制器 // // BaseLogicController.swift // 项目中通用的逻辑控制器import UIKit import TangramKitclass BaseLogicController: BaseCommonController {/// 根容器var rootContainer:TGBaseLayout!/// 头部容器var superHeaderContainer:TGBaseLayout!var superHea…

FFmpeg 头文件完美翻译之 libavfilter 模块

前言 众所周知,FFmpeg 的代码开发上手难度较高,源于官方提供的文档很少有包含代码教程相关的。要想熟练掌握 FFmpeg 的代码库开发,需要借助它的头文件,FFmpeg 把很多代码库教程都写在头文件里面。因此,熟读头文件的内…

【Rust自学】18.3. 模式(匹配)的语法

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 18.3.1. 匹配字面值 模式可以直接匹配字面值。看个例子: let x 1;match x {1…

在Mapbox GL JS中“line-pattern”的使用详解

在Mapbox GL JS中,line-pattern 是一种用于在地图上绘制带有图案的线条的样式属性。通过 line-pattern,你可以使用自定义的图像作为线条的图案,而不是使用纯色或渐变。 1. 基本概念 line-pattern: 该属性允许你指定一个图像作为线条的图案。…

WordPress自定义.js文件排序实现方法

在WordPress中,要将插件引用的.js文件放到所有.js文件之后加载,可以通过以下方法实现: 方法一:调整wp_enqueue_script的加载顺序 在插件的主文件中,使用wp_enqueue_script函数加载.js文件时,将$in_footer…

Spring Boot 2 快速教程:WebFlux 集成 Mongodb(三)

一、前言 上一讲用 Map 数据结构内存式存储了数据。这样数据就不会持久化,本文我们用 MongoDB 来实现 WebFlux 对数据源的操作。 什么是 MongoDB ? 官网:https://www.mongodb.com/ MongoDB 是一个基于分布式文件存储的数据库,由 C 语言编…

《redis4.0 通信模块源码分析(一)》

【redis导读】redis作为一款高性能的内存数据库,面试服务端开发,redis是绕不开的话题,如果想提升自己的网络编程的水平和技巧,redis这款优秀的开源软件是很值得大家去分析和研究的。 笔者从大学毕业一直有分析redis源码的想法&…