zoukankan      html  css  js  c++  java
  • 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() 将表类对象的成员属性值写入到数据库的二维表中。

  • 相关阅读:
    Git初级实践教程(图文)
    如何合并多个PPT
    优秀小工具集锦
    VS2015链接错误一则
    VisualStudio配色方案
    AI贪吃蛇(二)
    springMVC
    SSH三大框架的搭建整合(struts2+spring+hibernate)(转)
    生成图片验证码
    Spring JdbcTemplate详解(转)
  • 原文地址:https://www.cnblogs.com/jmilkfan-fanguiju/p/11825085.html
Copyright © 2011-2022 走看看