Openstack_SQLAlchemy_一对多关系表的多表插入实现

目录

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() 将表类对象的成员属性值写入到数据库的二维表中。

优秀的个人博客,低调大师

微信关注我们

原文链接:https://yq.aliyun.com/articles/237349

转载内容版权归作者及来源网站所有!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

相关文章

发表评论

资源下载

更多资源
Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的、适应高吞吐量的数据库方案。

Eclipse(集成开发环境)

Eclipse(集成开发环境)

Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括Java开发工具(Java Development Kit,JDK)。

Java Development Kit(Java开发工具)

Java Development Kit(Java开发工具)

JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。

Sublime Text 一个代码编辑器

Sublime Text 一个代码编辑器

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。