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.
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 nuevo | pre_init_hook |
| Poblar campos nuevos usando el ORM | post_init_hook |
| Corregir datos solo al pasar por una versión concreta | migrations/<version>/ |
| Revertir efectos secundarios al desinstalar | uninstall_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.