Ir al contenido

Scripts de migración: pre_init, post_init y end hooks

Cuándo usar cada hook y cómo migrar datos entre versiones sin perder consistencia
4 de julio de 2026 por
Scripts de migración: pre_init, post_init y end hooks
Atemi, Aitor Atencia

Odoo · Migración · Datos

Cuando una migración necesita transformar datos existentes —no solo instalar campos nuevos—, la lógica no va en un método del modelo: va en un hook de migración. Elegir el hook equivocado, o poner en post_init_hook algo que debería ir en pre_init_hook, es la forma más común de acabar con datos a medio transformar.

Logo Odoo Base de datos
Cada hook se ejecuta en un momento distinto del ciclo de instalación: el orden importa tanto como el código.

Orden

Qué hace cada hook y cuándo se ejecuta

  • pre_init_hook: antes de crear las tablas y campos del módulo. Útil para renombrar columnas que van a cambiar de tipo o de nombre, evitando que Odoo intente convertir datos incompatibles automáticamente.
  • post_init_hook: después de instalar el módulo, con el ORM ya disponible. Es el sitio correcto para poblar campos nuevos a partir de datos existentes.
  • uninstall_hook: al desinstalar, para limpiar datos externos o revertir cambios que el módulo hizo fuera del ORM estandar.
# __manifest__.py
{
    'name': 'Mi módulo',
    'pre_init_hook': 'pre_init_hook',
    'post_init_hook': 'post_init_hook',
}

# hooks.py
def pre_init_hook(env):
    env.cr.execute("""
        ALTER TABLE sale_order
        RENAME COLUMN old_ref TO client_order_ref_legacy
    """)

def post_init_hook(env):
    orders = env['sale.order'].search([('client_order_ref', '=', False)])
    for order in orders:
        order.client_order_ref = order.client_order_ref_legacy

SQL directo

Por qué pre_init_hook no usa el ORM

En pre_init_hook las tablas del modelo todavía no existen con la estructura nueva, así que no hay ORM utilizable para ese modelo. Se trabaja con env.cr.execute() directamente sobre SQL. Es potente pero peligroso: sin el ORM no hay validaciones, constraints ni record rules de por medio.

Odoo 17+

migrations/ para cambios entre versiones puntuales

# migrations/19.0.1.1/post-migrate.py
def migrate(cr, version):
    cr.execute("""
        UPDATE res_partner
        SET vat = UPPER(vat)
        WHERE vat IS NOT NULL
    """)

A diferencia de los hooks del manifest —que se ejecutan en cada instalación del módulo—, los scripts en migrations/<version>/ se ejecutan una única vez, exactamente al pasar por esa versión concreta del módulo. Es el mecanismo correcto para una corrección puntual de datos que no debe repetirse en instalaciones limpias.

Checklist

Antes de escribir un hook de migración

Necesitas...Usa
Renombrar/transformar columnas antes de crear el esquema nuevopre_init_hook
Poblar campos nuevos usando el ORMpost_init_hook
Corregir datos solo al pasar por una versión concretamigrations/<version>/
Revertir efectos secundarios al desinstalaruninstall_hook

Resumen

pre_init_hook es para SQL directo antes de que exista el esquema nuevo; post_init_hook es para poblar datos con el ORM ya disponible; los scripts en migrations/<version>/ son para correcciones puntuales que solo deben ejecutarse una vez al pasar por esa versión. Mezclar estos tres momentos es la causa más frecuente de datos a medio migrar.

en Odoo
Migrar módulos de Odoo 17/18 a 19
Checklist real: models.Constraint, vistas y pruebas de regresión