目录

Openstack 与 SQLAlchemy

SQLAlchemy 是 Python 语言下的一款开源软件,它提供了 SQL 工具包以及对象关系映射器(ORM)。SQLAlchemy 主要分为两个部分:SQLAlchemy CoreSQLAlchemy 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_machinesdatastores
# 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_keysbackref 指定了 Table virtual_machinesdatastores 之间的关系为 双向的一对多关系

详见:SQLAlchemy_定义(一对一/一对多/多对多)关系

  • Step 3: 定义 SQLAlchemy 的数据库操作接口函数, 这里定义了对 Table virtual_machinescreate 操作

    NOTE:因为我们希望实现多表插入,即一次性插入两张表的数据,所以只要定义对一张表的 SQLAlchemy creae 函数即可。但这一函数必须是对应表示 ‘一’ 的一张表。

    EG.Table virtual_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_machinesvalues 格式

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 VirtualMachineDatastore 时,指定了两者之间为 双向一对多 的关系,所以 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_一对多关系表的多表插入实现的更多相关文章

  1. MySQL数据库 crud语句 ifnull() 创建新账户 备份数据库 一对多关系 多对多(中间表) 外键约束 自关联 子查询注意事项 DML DDL DQL mysql面试题 truncate与delete的区别

    DML(data manipulation language): 它们是SELECT.UPDATE.INSERT.DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据进行操作的语言 DDL ...

  2. [Fluent NHibernate]一对多关系处理

    目录 写在前面 系列文章 一对多关系 总结 写在前面 上篇文章简单介绍了,Fluent Nhibernate使用代码的方式生成Nhibernate的配置文件,以及如何生成持久化类的映射文件.通过上篇的 ...

  3. hibernate中一对多关系中的inverse,cascade属性

    举例说明: 一对多关系的两张表:boy.girl(一个男孩可以多个女朋友) boy表结构 Field   Type        ------  -----------  name    varcha ...

  4. 《BI那点儿事—数据的艺术》理解维度数据仓库——事实表、维度表、聚合表

    事实表 在多维数据仓库中,保存度量值的详细值或事实的表称为“事实表”.一个按照州.产品和月份划分的销售量和销售额存储的事实表有5个列,概念上与下面的示例类似. Sate Product Mouth U ...

  5. laravel orm 中的一对多关系 hasMany

    个人对于laravel orm 中对于一对多关系的理解 文章表 article,文章自然可以评论,表 comment 记录文章的评论,文章和评论的关系就是一对多,一篇文章可以有多个评论. 在 comm ...

  6. Laravel5.1 模型 --远层一对多关系

    远层一对多我们可以通过一个例子来充分的了解它: 每一篇文章都肯定有并且只有一个发布者 发布者可以有多篇文章,这是一个一对多的关系.一个发布者可以来自于一个国家 但是一个国家可以有多个发布者,这又是一个 ...

  7. Php Laravel框架 多表关系处理 之 Eloquent一对多关系处理

    Php Laravel框架 多表关系处理 之 Eloquent一对多关系处理 本博文主要介绍 Laravel 框架中 Eloquent  对一对多关系的处理以及在 Laravel Administra ...

  8. JDBC上关于数据库中多表操作一对多关系和多对多关系的实现方法

    黑马程序员 我们知道,在设计一个Javabean的时候,要把这些BEAN 的数据存放在数据库中的表结构,然而这些数据库中的表直接又有些特殊的关系,例如员工与部门直接有一对多的关系,学生与老师直接又多对 ...

  9. 五、hibernate表与表之间的关系(一对多关系)

    数据库表与表之间的关系 一对多:一个学校可以有多个学生,一个学生只能有一个学校 多对多:一个学生可以有多个老师,一个老师可以教多个学生 一对一:一个人只能有一个身份证号,一个身份证号只能找到一个人 一 ...

随机推荐

  1. 【算法入门】深度优先搜索(DFS)

    深度优先搜索(DFS) [算法入门] 1.前言深度优先搜索(缩写DFS)有点类似广度优先搜索,也是对一个连通图进行遍历的算法.它的思想是从一个顶点V0开始,沿着一条路一直走到底,如果发现不能到达目标解 ...

  2. eclipse调试openstack的nova代码

    前段时间一直在研究openstack的nova部分的代码.特别想知道,怎样用eclipse来调试代码.也在论坛上问了别人.无果.最后还是自己摸索出了出路. 以下写出自己探索之路.我是用devstack ...

  3. html5酷炫效果链接收集

    HTML5 3D图片相册图片轮播动画   http://www.html5tricks.com/demo/html5-3d-gallery-animation/index.html 36种漂亮的CSS ...

  4. sql中关闭自增,并插入数据

    ET IDENTITY_INSERT 允许将显式值插入表的标识列中. 语法 SET IDENTITY_INSERT [ database.[ owner.] ] { table } { ON | OF ...

  5. #include <xxx.h>和#include "xxx.h"的区别

    <>代表在系统目录下查找该头文件(系统定义头文件) ""代表在用户目录下查找该头文件(自定义头文件)

  6. CSS初识

    CSS:层叠样式表,控制网页数据样式显示,使得数据的表现和内容分离 CSS的引入方式 使用元素内嵌样式表:例<a style=”font-size:40px”></a>表示在a ...

  7. PAT Advanced 1036 Boys vs Girls (25 分)

    This time you are asked to tell the difference between the lowest grade of all the male students and ...

  8. MySQL的运行模式及一些特性,引擎、事务、并发控制、优化总结

    一 MySQL总体架构 上图是<高性能MySQL>中对MySQL总体架构的描述,客户端对服务端的连接有很多条,有一个专门的处理组件,类似tomcat使用线程池处理请求.解析器负责解析sql ...

  9. [原创]Laravel 基于redis队列的解析

    目录 参考链接 本文环境 为什么使用队列 Laravel 中的队列 分发任务 任务队列 Worker Last-Modified: 2019年5月10日11:44:18 参考链接 使用 Laravel ...

  10. 【GDOI2014模拟】雨天的尾巴

    题目 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连 根拔起,以及田地里 ...