7. Desarrollando con Odoo (5). Campos relacionales calculados. Valor por defecto calculado. Funciones lambda
1. Introducción
Vamos a añadir 2 modelos nuevos project y history. Vamos amostrar de forma un poco laxa como estan relacionados. Se indica en la parte superior el padre y en la inferior los hijos
project
|--> sprint
|--> task
|--> history
|--> task
Podemos ver que de project cuelgan directamente sprint y history y que task tiene de padres a sprint y history.
También, como se indica en el video, vamos a eliminar los campos creation_date ya que por omisión, odoo incluye campos equivalentes.
2. Campo relacionado calculado Many2one
Las nuevas reglas del juego son:
- Solo habrá un sprint abierto por proyecto. El sprint abierto se caracteriza por tener el end_date mayor a la fecha de hoy
- A la tarea se le asignará un sprint abierto
- Para poder seleccionar el sprint, priomeramente se seleccionará un history padre, el cual nos apuntará a un proyecto, y como solo hay un único sprint abierto por proyecto, se seleccionará este como padre de la tarea.
- Una vez asignado el sprint, no se podrá cambiar. O sea solamente se puede asignar una vez
De entre todos los sprints que pueden ser padres de un task, vamos a elegir aquel que esté abierto en un proyecto. Solo habrá un sprint abierto por proyecto.
Para ver como se asigna el sprint y no volverlo a cambiar se puede hacer que dependa del campo "id" (@api_depends('id')).... Pero si metemos este decorador, ODOO NO ARRANCA!
Para ello se puede hacer un truco y es crear un campo calculado que coja el valor de id y que no se guarde en la BD, y meter el decorador @api_depends sobre dicho campo calculado
Ojo: lo que vamos a hacer es que el campo sprint dependa de history, con lo que si cambiamos el history, afectará al campo sprint y se acaba el problema
Veamos resumidamente lo que hay que hacer:
- En el modelo de task, hacer el campo sprint calculado aplicandole una función de cálculo _get_sprint()
- En la función de cálculo utilizar la api de búsqueda de los registros de un modelo self.env['ximoapp01.sprint'].search([condicion])
class task(models.Model): _name = 'ximoapp01.task' -------------- history = fields.Many2one("ximoapp01.history", ondelete="set null",help="Historia relacionada") sprint = fields.Many2one("ximoapp01.sprint", compute="_get_sprint", ondelete="set null", store= True, help="Macro tarea padre Sprint") @api.depends('history') def _get_sprint(self): for record in self: sprints = self.env['ximoapp01.sprint'].search([('project.id', '=', record.history.project.id)]) found = False for sprint in sprints: if not found: if isinstance(sprint.end_date, datetime.datetime): if sprint.end_date > datetime.datetime.now(): record.sprint = sprint.id found = True if not found: record.sprint = False
3. Campo relacionado calculado Many2many
Este caso es muy parecido al anterior.
Ahora vamos a asignar al modelo history todas la tecnologías utilizadas en cada una de la tareas que dependen de esta history sin duplicar ninguna.
Para ello:
- Le añadimos el atributo compute que apunta al método que calcula el valor del campo
- En dicha función de cálculo recorremos las task de la history y añadimos a la lista las technology
veamos el trozo de código que nos interesa del modelo
class history(models.Model): _name = 'ximoapp01.history' _description = 'ximoapp01.history' name = fields.Char(string= "Nombre", readonly=False, required=True, help="Nombre del Projecto" ) description = fields.Text() project = fields.Many2one("ximoapp01.project", ondelete="set null", help="Proyecto") tasks = fields.One2many(string="Tareas", comodel_name="ximoapp01.task", inverse_name='history') technologies = fields.Many2many(comodel_name="ximoapp01.technology", compute="_get_technologies") def _get_technologies(self): for record in self: technologies = None for task in record.tasks: if not technologies: technologies= task.technologies else: technologies = technologies + task.technologies record.technologies=technologies
4. Campo por defecto calculado. Funciones lambda
En este caso hay que dar a default el valor de la función que lo calcula sin entrecolimmar, pero primeramente debemos definir la función que realiza el cálculo del valor por defecto antes de declarar el campo!!!
Veamos el trozo de código que nos interesa
class task(models.Model): _name = 'ximoapp01.task' -------- def _get_definition_date(self): return datetime.datetime.now() definition_date = fields.Datetime(default=_get_definition_date)
Pero también podemos hacer uso de una función lambda, transformando 2 declaraciones separadas en una sola. Se ha comentado el código anterior
class task(models.Model): _name = 'ximoapp01.task' -------- #def _get_definition_date(self): # return datetime.datetime.now() #definition_date = fields.Datetime(default=_get_definition_date) definition_date = fields.Datetime(default= lambda d: datetime.datetime.now())
Comentarios
Publicar un comentario