Skip to content

Campos Avanzados y Métodos

En cualquier escenario de negocio real necesitamos más de un modelo. Además, son necesarios vínculos entre modelos. Uno puede imaginar fácilmente un modelo que contiene los clientes y otro que contiene la lista de usuarios. Es posible que deba consultar a un cliente o usuario en cualquier modelo de negocio existente.

Relación Many2many

many2many es una relación múltiple bidireccional: cualquier registro de un lado puede relacionarse con cualquier número de registros del otro lado. Por convención, los campos many2many tienen el sufijo _ids

test_ids = fields.Many2many("test_model", string="Tests")
for record in my_test_object.test_ids:
print(record.name)

Relación Many2one

La relación many2one es un simple enlace a otro objeto. cualquier registro de un lado puede relacionarse con un solo registro del otro lado. Por convención, los campos many2one tienen el sufijo _id

test_id = fields.Many2one("test_model", string="Test")

Relación One2many

La relación one2many es la inversa de many2one. El primer parámetro se llama comodel y el segundo parámetro es el campo que queremos invertir. Por convención, los campos one2many tienen el sufijo _ids. Se comportan como una lista de registros, lo que significa que el acceso a los datos debe hacerse en bucle:

test_ids = fields.One2many("test_model", "partner_id", string="Tests")
for test in partner.test_ids:
print(test.name)

Los campos se pueden calcular en lugar de leerlos directamente desde la base de datos utilizando el parámetro compute. Debe asignar el valor calculado al campo. Si usa los valores de otros campos, debe especificar esos campos usando depends().

El decorador del método depends() es utilizado por el ORM para activar el recálculo del campo siempre que alguna de sus dependencias haya sido modificada.

from odoo import models, fields, api
class TestComputed(models.Model):
_name = "test.computed"
total = fields.Float(compute="_compute_total")
amount = fields.Float()
@api.depends("amount")
def _compute_total(self):
for record in self:
record.total = 2.0 * record.amount

Por convención, los métodos vinculados a campos computados son privados, lo que significa que no se pueden llamar desde el nivel de presentación, solo desde el nivel de negocio. Los métodos privados tienen un nombre que comienza con un guión bajo .

Los campos computatos no se almacenan de forma predeterminada, se calculan y se devuelven cuando se solicitan. Establecer store=True los almacenará en la base de datos y habilitará automáticamente la búsqueda.

Los campos calculados son de solo lectura de forma predeterminada. Para permitir establecer valores en un campo calculado, use el parámetro inverso. Es el nombre de una función que invierte el cálculo y establece los campos relevantes:

En algunos casos, podría ser útil poder establecer un valor directamente.

from odoo import models, fields, api
class TestComputed(models.Model):
_name = "test.computed"
total = fields.Float(compute="_compute_total", inverse="_inverse_total")
amount = fields.Float()
@api.depends("amount")
def _compute_total(self):
for record in self:
record.total = 2.0 * record.amount
def _inverse_total(self):
for record in self:
record.amount = record.total / 2.0

Un método computado establece el campo, mientras que un método inverso establece las dependencias del campo. Se debe tener en cuenta que se llama al método inverso al guardar el registro, mientras que se llama al método compute en cada cambio de sus dependencias.

El mecanismo “onchange” proporciona una forma para que la interfaz del cliente actualice un formulario sin guardar nada en la base de datos cada vez que el usuario haya completado un valor de campo. Para lograr esto, definimos un método donde self representa el registro en la vista de formulario y lo decoramos con onchange() para especificar por qué campo se activa.

from odoo import models, fields, api
class TestOnchange(models.Model):
_name = "test.onchange"
name = fields.Char(string="Name")
description = fields.Char(string="Description")
partner_id = fields.Many2one("res.partner", string="Partner")
@api.onchange("partner_id")
def _onchange_partner_id(self):
self.name = "Document for %s" % (self.partner_id.name)
self.description = "Default description for %s" % (self.partner_id.name)

El mecanismo del decorador constrains() especifica qué campos están involucrados en la restricción, esta evalúa automáticamente cuando se modifica cualquiera de estos campos.

from odoo.exceptions import ValidationError
@api.constrains('date_end')
def _check_date_end(self):
for record in self:
if record.date_end < fields.Date.today():
raise ValidationError("The end date cannot be set in the past")
# all records passed the test, don't return anything

Un caso especial de campos computados son los campos relativos (proxy), que proporcionan el valor de un subcampo en el registro actual. Se definen estableciendo el parámetro relacionado y, al igual que los campos calculados normales, se pueden almacenar.

nickname = fields.Char(related='user_id.partner_id.name', store=True)

El valor de un campo relativo se obtiene siguiendo una secuencia de campos relacionales y leyendo un campo en el modelo alcanzado. La secuencia completa de campos a recorrer se especifica mediante el atributo related.

De forma predeterminada, los campos relativos son:

  • no almacenado
  • no copiado
  • solo lectura
  • calculado en modo superusuario