【ODOO14】odoo中的数据库迁移管理

本文详细介绍了Odoo中的数据库迁移管理,包括MigrationManager类的解析,版本处理规则,以及迁移脚本的执行流程。文章强调了版本号的书写规范和迁移脚本的目录结构,建议开发团队遵循一定的版本规则以避免问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

odoo中的数据库迁移管理

前言

在最近odoo开发时,出现了模型结构变更导致数据库升级失败的问题。在Boss的指导下,发现了那个在Django中使用了无数次的关键字migrate。原来odoo也提供了数据库迁移脚本工具,这个工具很简单,从开发的角度来说,有些地方的处理可以说很粗糙。但按照一定的规则去做odoo开发,不管的是大版本之间的迁移,还是小版本之间的迁移,这个工具起到的效果还是很棒的。

odoo 提供了 MigrationManager 类来管理数据库迁移。脚本路径:odoo/modules/migration.py

文档环境

  • version: 14.0

源码分析

MigrationManager

在odoo中,数据库迁移的实现是通过MigrationManager类实现的,这里分析下odoo/modules/migration.py这个文件。

_init_(self, cr, graph)
def __init__(self, cr, graph):
    self.cr = cr
    self.graph = graph
    self.migrations = defaultdict(dict)
    self._get_files()

该方法为MigrationManager的构造方法。它接受两个参数:

  • cr:当前数据库游标(db.cursor()),供后续处理数据库迁移操作数据库使用。
  • graph:要加载的模块节点图,供后续处理数据库迁移判断状态使用。
_get_files(self)

该方法在实例化MigrationManager时被调用,其作用是通过遍历模块节点图,获取每个模块的数据库迁移脚本文件路径,初始化到migrations中。

for pkg in self.graph:
    if not (hasattr(pkg, 'update') or pkg.state == 'to upgrade' or getattr(pkg, 'load_state', None) == 'to upgrade'):
        continue

        self.migrations[pkg.name] = {
            'module': get_scripts(get_resource_path(pkg.name, 'migrations')),
            'module_upgrades': get_scripts(get_resource_path(pkg.name, 'upgrades')),
            'upgrade': get_scripts(_get_upgrade_path(pkg.name)),
        }

另外在该方法中提供了以下两个闭包:

  • _get_upgrade_path(pkg):该闭包在odoo/odoo/upgradeodoo/odoo/addons/base/maintenance/migrations文件夹下扫描,如果在任一文件夹下找到以给定模块名命名的子文件夹,则返回子文件夹完整路径,否则返回None。供get_scripts闭包使用。
  • get_scripts(path):该闭包返回给定路径下后缀为.py的文件路径列表。
migrate_module(package, state)

该方法migrate_module,是处理数据库迁移的核心方法,接受以下两个参数:

  • package: 即模块或插件名。
  • stage:即处理阶段。数据库迁移分了以下三个阶段,用于在不同时机处理数据库迁移操作:
    • pre:在模块初始化之前执行。migrate_module(package, 'pre')
    • post:在模块初始化之后执行。migrate_module(package, 'post')
    • end:在所有模块更新后运行。migrate_module(package, 'end')

该方法提供了三个闭包方法

  • convert_version(version):该闭包将给定版本字符串简单处理并返回(迁移脚本中version的处理)。
  • _get_migration_versions(pkg, stage):该闭包处理并返回数据库迁移版本号码。
  • get_migration_files(pkg, version, stage):该闭包通过处理给定模块、给定版本和给定处理阶段,获取相应迁移脚本文件的完整路径。

脚本流程

当实例数据库的模型注册表发生变更时,会通过load_modules方法重新加载实例中的模块或插件,在此加载过程中执行了数据库迁移功能,即调用了MigrationManager.migrate_module方法。

核心处理流程如下:

  1. 数据库迁移条件检查:判断给定package对应的模块状态是否符合迁移条件,若不符合,不会继续以下步骤。
  2. 获取并格式化迁移前模块版本号,该版本号为__manifest__.py文件中的version值(odoo处理规则)。
  3. 获取并格式化给定模块的当前迁移版本号
  4. 比较迁移前模块版本号和给定模块的当前迁移版本号,如果当前迁移版本号迁移前模块版本号小,不会继续以下步骤。
  5. 获取给定模块对应的模块文件夹下的迁移脚本文件路径。
  6. 执行迁移脚本文件中的逻辑处理。

odoo处理version规则

manifest 文件中的版本号version的值,如果不是以当前主版本号(即服务版本号,比如14.0)开头,会被认定为模块版本号。但odoo会处理成以当前主版本号(即服务版本号,比如14.0)开头的完整版本号,存储到数据库。比如:

  • 在服务版本为14.0时,12.0.0.1会被认定为模块版本号,并最终被处理的完整版本号为14.0.12.0.0.1
  • 在服务版本为14.0时,0.1会被认定为模块版本号,并最终被处理的完整版本号为14.0.0.1
  • 在服务版本为14.0时,14.0.0.1会被认定为完整版本号,不会被处理。

比较好的实践是开发团队间约定一套版本规则,尽量在开发时,书写完整的版本号。避免出现不必要的麻烦。

迁移脚本中version的处理

该处理在convert_version中实现,处理时根据判断给定版本号字符串中.的数量处理出版本号,当数量>=2时,直接返回。否则,将当前主版本号(比如14.0)作为前缀拼接到给定版本号字符串返回。比如:

  • 给定版本字符串为0.0.1,将直接返回0.0.1
  • 给定版本字符串为0.1,将直接返回14.0.0.1

在获取迁移脚本路径时,会根据返回的版本字符串扫描文件夹,如果没找到,迁移程序就不会执行。既然如此,还是建议开发团队间约定一套版本规则,尽量在开发时,书写完整的版本号。避免出现不必要的麻烦。

使用规范

使用此数据库迁移功能,需要遵循以下规则,约定此文档对应的主版本(即服务版本)为14.0

  • 迁移管理代码遵循以下目录树结构:

        module_name
            |-- migrations
                |-- 1.0       						    # 不含服务版本号,只含模块版本号                      
                |   |-- pre-update_table_x.py
                |   |-- pre-update_table_y.py
                |   |-- post-create_plop_records.py
                |   |-- end-cleanup.py
                |   `-- README.txt                      # 不会被处理
                |-- 13.0.1.1                            # 不会被处理(只在 13.0 中被处理)
                |   |-- pre-delete_table_z.py
                |   `-- post-clean-data.py
                |-- 0.0.0                               # 在所有版本被处理
                |   `-- end-invariants.py               
                `-- foo.py                              # 不会被处理
    

    在需要执行数据库迁移的模块根目录下必须创建名为migrations的文件夹,其中包含按版本划分的文件夹。

    • 版本文件夹名可以不含服务版本号,只含模块版本号。

      比如:1.0。如果没有主版本数据库迁移需求(比如13.0升级到14.0),可以这样命名。因为程序处理会自动拼接主版本号。

    • 版本文件夹名也可以即含服务版本号,有含模块版本号。

      比如:13.0.1.1

    • 版本文件夹名还可以是一个特殊号码:0.0.0,此文件夹下的迁移文件将在任何版本更改时运行。

  • 迁移处理文件必须是以pre-post-end-开头的Python文件。

    • pre-在模块初始化之前执行。
    • post-在模块初始化之后执行。
    • end-在所有模块更新后运行。
  • 迁移文件必须是包含migrate(cr,installed_version)函数的python文件。

注意:在 pre 阶段,0.0.0 脚本首先运行,而在 postend 中,0.0.0 脚本最后运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值