Openstack_SQLAlchemy_一对多关系表的多表插入实现
目录
Openstack 与 SQLAlchemy
SQLAlchemy 是 Python 语言下的一款开源软件,它提供了 SQL 工具包以及对象关系映射器(ORM)。SQLAlchemy 主要分为两个部分:SQLAlchemy Core 和 SQLAlchemy ORM。
- 前者包括了 SQL 语言表达式/数据引擎/连接池等, 主要实现了:连接不同类型的数据库,提交查询和更新请求,定义数据库数据类型和定义 Schema 等功能。
- 后者提供了数据映射模式,将程序中的对象数据映射成数据库中的关系数据。但不可避免的会因为映射而降低程序效率。
SQLAlchemy 最大的好处在于,当数据从一中数据库管理器系统迁移到另外一种数据库管理系统时(EG. MySQL –> PostgreSQL),Python 程序员可以不用修改或者修改少量配置文件后仍能正常运行。所以 SQLAlchemy 是 Python 语言中较为常用的一款数据库 ORM 工具,也是 Openstack 默认支持 ORM 工具。
本篇主要记录了,我们如何对数据库中 一对多 的关系表进行多表插入。
一个多表插入的 Demo
在这个 Demo 中定义了 Table: virtual_machines 和 Table:datastores。这两个实体对象之间的关系为:一个 VirtualMachine 可以对应拥有多个 Datastore 。
- Step 1: 在数据库初始化模块中中定义 Table
virtual_machines和datastores
# octopunch/octopunch/db/sqlalchemy/migrate_repo/versions/001_octopunch_init.py
def define_tables(meta):
virtual_machines = Table(
'virtual_machines', meta,
Column('uuid', String(length=45), primary_key=True, nullable=False),
Column('vm_value', String(length=255)),
Column('name', String(length=255)),
mysql_engine='InnoDB'
)
datastores = Table(
'datastores', meta,
Column('uuid', String(length=45), primary_key=True, nullable=False),
Column('ds_value', String(length=255)),
Column('name', String(length=255)),
Column('virtual_machine_uuid', String(length=45),
ForeignKey('virtual_machines.uuid')),
mysql_engine='InnoDB'
)
NOTE: Table datastores 的外键值为 virtual_machines 的主键值
- Step 2: 在 SQLAlchemy 的 models 模块中定义对应的 class,并且将它们之间的关系设定为为一对多的关系
数据库二维表中的一行记录成为了一个类,一个字段成为了一个类属性
# octopunch/octopunch/db/sqlalchemy/models.py
class VirtualMachine(BASE, OctopunchBase):
"""Represents the virtual machine list."""
__tablename__ = 'virtual_machines'
uuid = Colmn(String(45), primary_key=True, primary_key=True)
vm_value = Column(String(255))
name = Column(String(255))
datastores = relationship('Datastore', backref='virtual_machines',
foreign_keys='Datastore.virtual_machine_uuid',
primaryjoin='VirtualMachine.uuid =='
'Datastore.virtual_machine_uuid')
class Datastore(BASE, OctopunchBase):
"""Represents the datastore list."""
__tablename__ = 'datastores'
uuid = Colmn(String(45), primary_key=True, primary_key=True)
ds_value = Column(String(45))
name = Column(String(255))
virtual_machine_uuid = Column(String(45),
ForeignKey('virtual_machines.uuid'))
NOTE:SQLAlchemy 提供的 relationship() 函数用于定义表与表之间的关系,通过参数 foreign_keys 和 backref 指定了 Table virtual_machines 和 datastores 之间的关系为 双向的一对多关系 。
详见:SQLAlchemy_定义(一对一/一对多/多对多)关系
- Step 3: 定义 SQLAlchemy 的数据库操作接口函数, 这里定义了对 Table
virtual_machines的 create 操作
NOTE:因为我们希望实现多表插入,即一次性插入两张表的数据,所以只要定义对一张表的 SQLAlchemy creae 函数即可。但这一函数必须是对应表示 ‘一’ 的一张表。
EG.Tablevirtual_machines:
# octopunch/octopunch/db/sqlalchemy/api.py
def _resource_refs(resource_dict, resource_class):
resource_ref = resource_class()
for k, v in resource_dict.items():
resource_ref[k] = v
return resource_ref
@require_context
def virtual_machine_create(context, values):
datastores = values.pop('datastores')
# 将键值对 'datastores': '...' 中的 Str(datastores) 类型对象替换为 models.Datastore(datastores) 对象
values['datastores'] = [_resource_refs(datastore, models.Datastore)
for datastore in datastores]
if not values.get('uuid'):
values['uuid'] = str(uuid.uuid4())
virtual_machine_ref = models.VirtualMachine()
virtual_machine_ref.update(values) # update 类 VirtualMachine 实例对象 virtual_machine_ref 的成员属性值
session = get_session()
with session.begin():
session.add(virtual_machine_ref)
return virtual_machine_ref
先看看,接口函数 virtual_machine_create(context, values) 中的形参 values 就是要写入到数据库中的数据。values 是一个 Dict 的数据类型对象。其 key 为数据库表的字段名, value 为字段对应的值。
一般来说,形参 values 的键值对元素和数据库表中的字段是相匹配的,个数也会相同。
但需要注意的是: 如果希望对 一对多 或 多对多 的关系表进行多表插入,那么就需要将表示为 ‘多’ 的一方的插入表数据也合并为存放于该 values 中一个键值对元素。
EXAMPLE: Table virtual_machines 的 values 格式
virtual_machine = {
'uuid': '<virtual_machine_uuid>',
'vm_value': '<virtual_machine_value>',
'name': '<virtual_machine_name>',
# 必须为 Table datastores 的 table_name
'datastores': '[
{
"name": "<datastore_1_name>",
...
},
{
"name": "<datastore_2_name>",
...
},
...
]'
}
为什么只需要按照这样的合适定义 values 就可以实现我们想要的结果呢?
是因为我们在 models 模块定义 class VirtualMachine 和 Datastore 时,指定了两者之间为 双向一对多 的关系,所以 SQLAlchemy 会在 VirtualMachine 中添加 datastores 成员属性。SQLAlchemy 会自动为该属性赋予上述字典中 virtual_machine['datastores'] 的值。
这个动作在语句 virtual_machine_ref.update(values) 处执行。
注意:请回过头在看看 Step 3 的代码实现。
- Step 4: 为
octopunch.octopunch.db.sqlalchemy.api.virtual_machine_create()传入 values 的实参
实际上你可以在任何地方,调用并为其传入实参octopunch.octopunch.db.sqlalchemy.api.,所以这里就不给出实例代码了。
virtual_machine_create()
可以参考: Openstack 通过 SQLAlchemy-ORM 访问数据库
小结
如何通过 SQLAlchemy 为 一对多 关系表进行多表插入?
- 需要在 models 模块中定义表的类,并指定表之间的关系
- 定义 SQLAlchemy 的操作接口函数时,只需要定义一张表对应的 create 函数即可
- create 函数的形参数 values 的格式遵守上述 EXAMPLE 的格式
- 在 create 函数中要实例化两张表对应在 models 模块中的类对象
本质上,该 Demo 就是对 SQLAlchemy 的一次 ORM 操作 —— 将对二维表的操作转化为对类对象操作的方式。
1. 实例化得到 models 模块中的表类对象。
2. 调用表类对象的 update 函数将需要写入到数据库中的数据更新到表类对象的成员属性值。
3. 创建连接数据库的 session 对象。
4. 调用 session.add() 将表类对象的成员属性值写入到数据库的二维表中。
Openstack_SQLAlchemy_一对多关系表的多表插入实现的更多相关文章
- MySQL数据库 crud语句 ifnull() 创建新账户 备份数据库 一对多关系 多对多(中间表) 外键约束 自关联 子查询注意事项 DML DDL DQL mysql面试题 truncate与delete的区别
DML(data manipulation language): 它们是SELECT.UPDATE.INSERT.DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据进行操作的语言 DDL ...
- [Fluent NHibernate]一对多关系处理
目录 写在前面 系列文章 一对多关系 总结 写在前面 上篇文章简单介绍了,Fluent Nhibernate使用代码的方式生成Nhibernate的配置文件,以及如何生成持久化类的映射文件.通过上篇的 ...
- hibernate中一对多关系中的inverse,cascade属性
举例说明: 一对多关系的两张表:boy.girl(一个男孩可以多个女朋友) boy表结构 Field Type ------ ----------- name varcha ...
- 《BI那点儿事—数据的艺术》理解维度数据仓库——事实表、维度表、聚合表
事实表 在多维数据仓库中,保存度量值的详细值或事实的表称为“事实表”.一个按照州.产品和月份划分的销售量和销售额存储的事实表有5个列,概念上与下面的示例类似. Sate Product Mouth U ...
- laravel orm 中的一对多关系 hasMany
个人对于laravel orm 中对于一对多关系的理解 文章表 article,文章自然可以评论,表 comment 记录文章的评论,文章和评论的关系就是一对多,一篇文章可以有多个评论. 在 comm ...
- Laravel5.1 模型 --远层一对多关系
远层一对多我们可以通过一个例子来充分的了解它: 每一篇文章都肯定有并且只有一个发布者 发布者可以有多篇文章,这是一个一对多的关系.一个发布者可以来自于一个国家 但是一个国家可以有多个发布者,这又是一个 ...
- Php Laravel框架 多表关系处理 之 Eloquent一对多关系处理
Php Laravel框架 多表关系处理 之 Eloquent一对多关系处理 本博文主要介绍 Laravel 框架中 Eloquent 对一对多关系的处理以及在 Laravel Administra ...
- JDBC上关于数据库中多表操作一对多关系和多对多关系的实现方法
黑马程序员 我们知道,在设计一个Javabean的时候,要把这些BEAN 的数据存放在数据库中的表结构,然而这些数据库中的表直接又有些特殊的关系,例如员工与部门直接有一对多的关系,学生与老师直接又多对 ...
- 五、hibernate表与表之间的关系(一对多关系)
数据库表与表之间的关系 一对多:一个学校可以有多个学生,一个学生只能有一个学校 多对多:一个学生可以有多个老师,一个老师可以教多个学生 一对一:一个人只能有一个身份证号,一个身份证号只能找到一个人 一 ...
随机推荐
- python学习第五十四天hashlib模块的使用
hash算法 hash也做散列,也称为哈希,主要用于信息安全领域中加密算法,hash就是找一种数据内容和数据存放地址直接的映射关系. md5算法 md5讯息算法,广泛使用密码函数 md5算法的特点 1 ...
- 权限控制(vue)
权限控制(vue) 经常会遇到,角色权限控制问题,若是页面控制,倒好说,可如果是当前页面部分可见不可见,这就有些麻烦,如果加上条件就更加苛刻.之前只是简单的v-if进行控制,如今想试试指令(网上一直有 ...
- 卸载OpenIV
最近把 GTA5 卸载了,于是也想把用来修改 MOD 的 OpenIV 也卸载了. 结果在设置中,进行卸载的时候,弹出这个窗口 解决方案 1.首先打开 文件所在位置 2.右键,选择 属性,打开文件所在 ...
- 剑指offer-二叉搜索树与双向链表-python
题目描述 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向.. # -*- coding:utf-8 -*- # class TreeN ...
- 执行命令npm publish报错:403 Forbidden - PUT https://registry.npmjs.org/kunmomotest2 - You cannot publish over the previously published versions: 0.0.1.
前言 执行命令npm publish报错:403 Forbidden - PUT https://registry.npmjs.org/kunmomotest2 - You cannot publis ...
- 牛客练习赛49 E 筱玛爱游戏 (线性基+博弈)
链接:https://ac.nowcoder.com/acm/contest/946/E 来源:牛客网 筱玛爱游戏 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他 ...
- Codeforces 935 简单几何求圆心 DP快速幂求与逆元
A #include <bits/stdc++.h> #define PI acos(-1.0) #define mem(a,b) memset((a),b,sizeof(a)) #def ...
- Thymeleaf 整理
1.标准变量表达式: thymeleaf中的变量表达式使用${变量名}的方式获取其中的数据 th:text="" 是thymeleaf的一个属性,用于文本的显示 如:<spa ...
- java 通过反射获取数组
1.创建数组.设置数组元素.访问数组 一维数组: 多维数组: public Class<?> getComponentType() 返回表示数组组件类型的 Class.如果此类不表示数组类 ...
- #pragma 的使用(转)
尽管 C 和 C++ 都已经有标准,但是几乎每个编译器 (广义,包含连接器等) 扩展一些 C/C++ 关键字. 合理地应用这些关键字,有时候能使我们的工作非常方便.下面随便说说 Visual C++ ...