Introduction
El campo Many2One es uno de los bloques de construcción fundamentales del modelo de datos de Odoo. Cada vez que vinculas un pedido de venta a un cliente, asignas un producto a una categoría o conectas una tarea a un proyecto, estás trabajando con una relación Many2One. Es el tipo de campo relacional más común en Odoo, y entender cómo funciona es esencial para cualquiera que esté realizando un desarrollo o personalización seria de Odoo.
Desde una perspectiva empresarial, los campos Many2One son los que le dan a Odoo su coherencia como sistema integrado. Sin ellos, cada módulo sería una isla. Con ellos, los datos fluyen naturalmente de un registro a otro, y los usuarios pueden navegar entre documentos relacionados sin pensar nunca en la estructura de la base de datos.
Esta guía cubre lo que almacena el campo Many2One, cómo se comporta en el ORM de Odoo y en la interfaz, cómo crearlo y configurarlo utilizando Odoo Studio o Python, y casos de uso reales de negocios de CRM, Ventas, Inventario y Contabilidad.
What is the Many2One Field in Odoo
En el ORM de Odoo, un campo Many2One crea un enlace de un registro a exactamente un registro en otro modelo. El nombre describe la relación desde la perspectiva del modelo actual: muchos registros aquí pueden apuntar a un registro allí. Por ejemplo, muchos pedidos de venta pueden apuntar a un cliente, y muchos productos pueden pertenecer a una categoría de producto.
A nivel de base de datos, un campo Many2One almacena una clave externa en la tabla actual. Si un pedido de venta está vinculado al ID de cliente 42, la columna partner_id en la tabla sale_order contiene el entero 42. Odoo maneja automáticamente la unión y la obtención del nombre del registro relacionado.
En la interfaz de usuario, un campo Many2One aparece como un menú desplegable o un campo de entrada tipo autocompletar. Los usuarios pueden comenzar a escribir un nombre, y Odoo filtra los registros coincidentes en tiempo real. Seleccionar uno establece el enlace. El campo muestra el nombre del registro vinculado, no su ID interno. Esto lo convierte en uno de los tipos de campo más naturales desde el punto de vista de la experiencia del usuario.
Así es como se ve en una definición de modelo de Python:
from odoo import fields, models
class SaleOrder(models.Model):
_inherit = 'sale.order'
x_account_manager_id = fields.Many2One(
comodel_name='res.users',
string='Account Manager',
ondelete='set null',
)
El parámetro comodel_name es el nombre técnico del modelo al que estás vinculando. El parámetro ondelete controla lo que sucede con el registro actual si se elimina el registro vinculado. Las tres opciones son cascade (eliminar también el registro actual), set null (limpiar el enlace) y restrict (bloquear la eliminación si algún registro apunta a él).
En Odoo Studio, el campo Many2One aparece bajo la etiqueta Many2One en el selector de campos. Cuando agregas uno a través de Studio, eliges el modelo objetivo de una lista, y Studio maneja la creación del campo. Esto lo convierte en uno de los campos más accesibles de Odoo Studio para establecer relaciones sin escribir código.
Cómo funciona el campo
Cuando lees un campo Many2One a través del ORM de Odoo, obtienes un conjunto de registros que contiene el registro vinculado. Si el campo está vacío, obtienes un conjunto de registros vacío. En Python, puedes acceder al registro relacionado directamente y navegar a sus campos usando la notación de punto:
order = self.env['sale.order'].browse(1)
customer_name = order.partner_id.name
customer_city = order.partner_id.city
Esta navegación encadenada es uno de los aspectos más convenientes del marco de Odoo. No necesitas escribir uniones explícitas o consultas separadas. El ORM maneja el trabajo de la base de datos en segundo plano.
Al leer a través de la API XML-RPC, un campo Many2One devuelve una lista con dos elementos: el ID entero del registro vinculado y su nombre de visualización. Por ejemplo, [42, "Acme Corp"]. Si el campo está vacío, devuelve False. Esto es importante saberlo al procesar las respuestas de la API en tus scripts.
Atributos Clave del Campo
Estas son las propiedades más importantes que puedes configurar en un campo Many2One en el marco de Odoo:
- comodel_name: El nombre técnico del modelo objetivo. Este es el único parámetro requerido.
- ondelete: Lo que sucede con el registro actual cuando se elimina el registro vinculado. Las opciones son
'cascade','set null'y'restrict'. Por defecto es'set null'. - domain: Un filtro que restringe qué registros puede seleccionar el usuario en el menú desplegable. Por ejemplo,
domain=[('customer_rank', '>', 0)]limita la selección de socios solo a clientes. - context: Valores de contexto adicionales pasados al abrir el registro relacionado o el menú desplegable. Útil para rellenar campos automáticamente en registros relacionados recién creados.
- required: Hace que el campo sea obligatorio. El registro no se puede guardar a menos que este campo esté establecido.
- readonly: Impide que los usuarios cambien el registro vinculado. Útil cuando el enlace se establece programáticamente y no debe ser alterado manualmente.
- delegate: Cuando se establece en
True, todos los campos del modelo relacionado se vuelven directamente accesibles en el modelo actual. Esto se utiliza para la herencia de modelos en el desarrollo de Odoo, no para campos relacionales regulares.
Cómo Aparece en las Vistas
En las vistas de formulario, un campo Many2One se representa como un menú desplegable con un campo de búsqueda. Los usuarios pueden escribir un nombre parcial para filtrar la lista. También pueden hacer clic en el icono de flecha junto al campo para abrir el registro vinculado directamente, lo cual es muy útil para navegar entre documentos relacionados sin pasar por los menús.
En las vistas de lista, los campos Many2One muestran el nombre del registro vinculado. Soportan operaciones de agrupación: puedes agrupar una lista de órdenes de venta por cliente, o una lista de tareas por proyecto. Esta agrupación es una de las características más utilizadas en los informes de Odoo.
En las vistas de búsqueda, los campos Many2One pueden ser utilizados como filtros y criterios de agrupación. Cuando buscas por cliente en el pipeline de CRM, estás filtrando en un campo Many2One.
El Reciprocal One2Many
Cada relación Many2One tiene un reverso natural: el One2Many. Si los pedidos de venta se vinculan a un cliente a través de Many2One, el registro del cliente puede exponer una lista de todos los pedidos de venta vinculados a través de un campo One2Many. En el desarrollo de Odoo, es una buena práctica crear ambos lados de la relación. Esto permite a los usuarios navegar desde el formulario del cliente a todos sus pedidos sin realizar una búsqueda por separado. El campo One2Many no añade una columna a la base de datos; se calcula a partir de la clave externa Many2One en el otro lado.
Casos de Uso Empresarial
El campo Many2One está presente en todas partes en una implementación estándar de Odoo. Aquí hay cinco ejemplos prácticos de flujos de trabajo empresariales reales.
CRM: Vinculando Leads a Vendedores
En el módulo CRM de Odoo, cada lead u oportunidad tiene un campo user_id, que es un Many2One que apunta a res.users. Este es el vendedor responsable del lead. Los gerentes pueden filtrar el embudo por vendedor, ver las tasas de conversión por representante y asignar leads en bloque. El campo Many2One hace posible este tipo de segmentación e informes sin desarrollo personalizado. Si deseas agregar un segundo vendedor o un campo de gerente de cuentas dedicado, simplemente agregas otro campo Many2One que apunte al mismo modelo.
Ventas: Conectando Pedidos a Clientes y Listas de Precios
Un pedido de venta en Odoo tiene al menos dos campos Many2One importantes: partner_id (el cliente, vinculado a res.partner) y pricelist_id (la lista de precios, vinculada a product.pricelist). Cuando un vendedor selecciona un cliente, Odoo puede completar automáticamente la lista de precios, los términos de pago y la dirección de entrega basándose en el registro del cliente. Esta población automática es impulsada por métodos onchange que leen el valor Many2One y llenan los campos relacionados. Es uno de los beneficios más visibles de un modelo de datos de Odoo bien estructurado.
Inventario: Productos y Categorías
Cada producto en Odoo pertenece a una categoría de producto a través de un campo Many2One (categ_id en product.template). La categoría de producto controla las cuentas contables para el costo de bienes vendidos y los ingresos, los métodos de valoración y las estrategias de eliminación en los almacenes. Obtener la asignación de categoría correcta en cada producto es crítico para un informe financiero correcto. Un campo Many2One hace que esta asignación sea simple: un desplegable por producto, un registro de categoría compartido entre cientos de productos.
Contabilidad: Asientos Contables y Diarios
Cada asiento contable en Odoo está vinculado a un diario contable a través de un campo Many2One (journal_id en account.move). El diario determina la secuencia utilizada para la numeración de documentos, el tipo de entrada (venta, compra, banco, efectivo, misceláneo) y, en algunos casos, las cuentas de débito y crédito predeterminadas. Seleccionar el diario incorrecto en una factura de proveedor o un pago crea entradas en la sección incorrecta del libro mayor. El campo Many2One aquí no es solo una conveniencia; es un punto de control para la precisión contable.
Gestión de Proyectos: Tareas y Proyectos
En el módulo de Proyectos de Odoo, cada tarea pertenece a un proyecto a través de un campo Many2One (project_id en project.task). Este único enlace determina qué progresión de etapa sigue la tarea, qué miembros del equipo pueden acceder a ella y cómo se asignan las hojas de tiempo. Para las empresas de servicios profesionales que facturan por proyecto, el enlace Many2One entre las hojas de tiempo, las tareas y el proyecto principal es la columna vertebral del reconocimiento de ingresos y los flujos de trabajo de facturación.
Creación o Personalización del Campo Many2One
Hay tres formas principales de añadir un campo Many2One a un modelo de Odoo, dependiendo de tu contexto técnico y enfoque de implementación.
Usando Odoo Studio (Sin Código)
Odoo Studio es la herramienta de personalización de bajo código integrada. Para añadir un campo Many2One sin escribir ningún código:
- Abre Odoo Studio desde el menú principal.
- Navega hasta el formulario donde deseas el campo.
- Arrastra un campo Many2One desde el selector de campos al formulario.
- En el panel de propiedades, elige el modelo objetivo de la lista.
- Establece la etiqueta y cualquier filtro de dominio opcional para restringir qué registros pueden seleccionar los usuarios.
- Guarda y cierra Studio.
Studio crea el campo con un prefijo x_studio_ y lo añade automáticamente a la vista del formulario. El campo es inmediatamente funcional: los usuarios pueden abrir el menú desplegable, buscar registros vinculados y seleccionar uno. Esta es una de las formas más rápidas de extender un formulario con un enlace relacional, y no requiere conocimientos técnicos más allá de entender qué representan los dos modelos en tu negocio.
Usando Python en un Módulo Personalizado
Para los desarrolladores que construyen módulos de Odoo, los campos Many2One se definen directamente en Python. Este es el enfoque recomendado para cualquier desarrollo de Odoo que necesite ser controlado por versiones y desplegado en múltiples entornos:
from odoo import fields, models
class ProjectTask(models.Model):
_inherit = 'project.task'
x_client_contact_id = fields.Many2One(
comodel_name='res.partner',
string='Contacto del Cliente',
domain=[('type', '=', 'contact')],
ondelete='set null',
help='El contacto principal en el cliente para esta tarea.',
)
Después de definir el campo en el modelo, inclúyelo en la vista XML relevante y ejecuta una actualización para aplicar los cambios en la base de datos. Este enfoque brinda un control total sobre los filtros de dominio, el comportamiento de eliminación y la integración con métodos de cálculo y restricciones. Es el enfoque estándar de la guía del desarrollador de Odoo para campos relacionales en módulos de producción.
Al crear un Many2One como parte de la personalización de Odoo, también es una buena práctica agregar el campo correspondiente One2Many en el modelo relacionado para que los usuarios puedan navegar en ambas direcciones de la relación:
class ResPartner(models.Model):
_inherit = 'res.partner'
x_task_ids = fields.One2Many(
comodel_name='project.task',
inverse_name='x_client_contact_id',
string='Tareas Relacionadas',
)
Usando la API XML-RPC
Si estás gestionando personalizaciones de Odoo programáticamente, por ejemplo, a través de un script de implementación o un cuaderno de configuración remota, puedes crear campos Many2One a través de la API XML-RPC:
field_id = models.execute_kw(
ODOO_DB, uid, ODOO_API_KEY,
'ir.model.fields', 'create',
[{
'name': 'x_client_segment_id',
'field_description': 'Segmento del Cliente',
'model_id': model_id,
'ttype': 'many2one',
'relation': 'res.partner.category',
'on_delete': 'set null',
'state': 'manual',
}]
)
La clave relation especifica el modelo objetivo. La clave on_delete establece el comportamiento de eliminación. Al crear a través de la API, recuerda siempre crear también el campo One2Many recíproco en el modelo relacionado para que la navegación funcione desde ambos lados de la relación. Esta es una de las reglas obligatorias en las configuraciones remotas de Dasolo para cualquier creación de campo Many2One.
Mejores Prácticas
1. Siempre crea el One2Many recíproco
Cuando agregas un campo Many2One a un modelo, crea también el correspondiente One2Many en el modelo relacionado. Esto no te cuesta una columna adicional en la base de datos, pero hace que la navegación sea mucho más natural para los usuarios. Sin ello, los usuarios no tienen forma de ver desde el formulario del cliente qué tareas, pedidos o registros personalizados están vinculados a ellos.
2. Usa filtros de dominio para restringir la selección
Un campo Many2One que apunta a res.partner da acceso a todos los socios por defecto, incluidos proveedores, clientes, usuarios internos y direcciones de entrega. Si tu lógica empresarial solo tiene sentido para clientes, agrega un filtro de dominio como domain=[('customer_rank', '>', 0)]. Esto reduce el ruido en el menú desplegable y evita que los usuarios hagan selecciones incorrectas que parecen válidas pero producen resultados erróneos más adelante.
3. Elija ondelete con cuidado
El comportamiento de ondelete importa más de lo que parece. Usar 'cascade' significa que al eliminar el registro vinculado también se eliminarán todos los registros que apuntan a él. Esto puede causar eliminaciones masivas accidentales si no se pretende. En la mayoría de los escenarios comerciales, 'set null' es la opción más segura: elimina el enlace sin borrar nada. Use 'restrict' cuando el registro vinculado nunca deba ser eliminado mientras algo apunte a él, por ejemplo, una categoría de producto que tenga productos asignados.
4. Evite duplicar datos que deberían ser un Many2One
Un error común en los primeros proyectos de personalización de Odoo es agregar un campo char para almacenar un nombre de empresa o una etiqueta de categoría, cuando un Many2One que apunta a un modelo existente sería el enfoque correcto. Los campos char para valores que ya existen como registros en otro modelo crean duplicación de datos, hacen que el filtrado y la agrupación sean poco fiables, y producen inconsistencias cuando los nombres cambian. Si los datos que necesita residen en otro modelo, use un Many2One.
5. Use contexto para rellenar registros relacionados
El atributo context en un campo Many2One le permite pasar valores predeterminados cuando los usuarios crean un nuevo registro vinculado directamente desde el menú desplegable. Por ejemplo, si un Many2One apunta a un contacto dentro de un proyecto, puede rellenar automáticamente el proyecto en el nuevo registro de contacto usando contexto. Esto reduce la entrada manual y ayuda a mantener la consistencia de los datos cuando los usuarios crean registros relacionados sobre la marcha.
Errores Comunes
Olvidar el One2Many recíproco
Agregar un campo Many2One sin crear el One2Many inverso en el modelo relacionado es el descuido más común en la personalización de Odoo. El resultado es un enlace unidireccional: puede ver el registro vinculado desde el modelo actual, pero desde el registro vinculado no tiene forma de encontrar todos los registros que apuntan a él. Los usuarios comienzan a quejarse de que no pueden encontrar registros relacionados, y alguien termina construyendo una búsqueda o informe personalizado para compensar la falta de un campo inverso.
Usar eliminación en cascada sin pensarlo bien
Establecer ondelete='cascade' en un Many2One que vincula registros operativos a un registro maestro puede causar una pérdida de datos grave. Si un usuario archiva o elimina una categoría de producto, y todos los productos vinculados a ella tienen eliminación en cascada, cada producto en esa categoría desaparece. En la mayoría de los casos, set null o restrict es el comportamiento apropiado para los datos comerciales.
No verificar si es False al navegar en Python
Cuando un campo Many2One está vacío, leerlo devuelve un conjunto de registros vacío en Python, que es falso. Si su código hace order.partner_id.name sin verificar si partner_id está establecido, devolverá una cadena vacía en lugar de generar un error. Eso es a menudo aceptable, pero si navega varios niveles de profundidad (order.partner_id.country_id.name) y cualquier enlace en la cadena está vacío, obtiene una cadena vacía al final, lo que puede producir silenciosamente una salida incorrecta en informes o correos electrónicos. Siempre verifique conjuntos de registros vacíos cuando el campo no sea obligatorio.
Apuntando al modelo equivocado
En Odoo, res.partner se utiliza para clientes, proveedores, contactos y empresas a la vez. Un Many2One que apunta a res.partner sin un filtro de dominio da acceso a todos ellos. Si pretendías que el campo fuera solo para clientes pero olvidaste el dominio, los vendedores verán usuarios internos, direcciones de entrega y contactos de proveedores en el desplegable. Siempre define un filtro de dominio que coincida con la intención comercial real del campo.
Abusar de Many2One donde un campo de Selección sería suficiente
Si los valores vinculados son una lista pequeña y fija que nunca cambia, un campo de Selección suele ser más simple y más eficiente que un Many2One. Los campos Many2One requieren un modelo separado con registros, y añaden una unión de base de datos en cada consulta. Para algo como un estado con tres o cuatro opciones, un campo de Selección es más limpio. Usa Many2One cuando el conjunto de valores posibles sea grande, gestionado por usuarios o compartido entre múltiples modelos.
Conclusión
El campo Many2One está en el corazón de cómo Odoo conecta datos a través de módulos. Entenderlo no es solo una preocupación de desarrolladores. Los analistas de negocio, consultores funcionales y usuarios avanzados que desean extender Odoo con Studio se benefician de saber qué hace un Many2One, cuándo usar uno y qué tener en cuenta.
Los puntos clave a recordar: siempre crea el recíproco One2Many para que la navegación funcione desde ambos lados, usa filtros de dominio para mantener los desplegables limpios y relevantes, elige deliberadamente tu comportamiento ondelete y evita usar Many2One donde un campo de Selección más simple haría el trabajo.
Ya sea que estés configurando un campo a través de Odoo Studio, escribiendo un módulo de Python personalizado o gestionando tu modelo de datos de Odoo a través de la API XML-RPC, obtener los campos relacionales correctos desde el principio hace que tu implementación sea más confiable y mucho más fácil de mantener con el tiempo.
En Dasolo, ayudamos a las empresas a implementar, personalizar y optimizar Odoo en todos los departamentos. Ya sea que necesites ayuda para diseñar un modelo de datos limpio, agregar campos relacionales a tus formularios o construir un módulo completo de Odoo desde cero, nuestro equipo está aquí para apoyarte. Contáctanos y hablemos sobre tu proyecto de Odoo.