Muy bien, finalmente llegó el día tan esperado. Hoy señores es cuando deben recordar el sudor y las lágrimas que han dejado en el camino, porque de algún lado tendrán que sacar la fuerza necesaria para afrontar La Prueba y de qué otro lugar van a sacar ustedes fortaleza, si no es del recuerdo del gran esfuerzo que han hecho para llegar hasta aquí. Recuerden esta palabra “Acusmata”, si la olvidan se perderán y no todos tenemos una Ariadna que nos alcance un hilo para encontrar el camino de regreso.

Manos a la obra

Primer paso: tener un problema para solucionar

Vamos a desarrollar un modulo que nos permita administrar los integrantes de la Orden Pitagórica de Odoo. Empezaremos con un diagrama de clases simplificado y a medida que avancemos en los grados iremos haciendo mas complejo el desafío, para poder ir aplicando nuevos conocimientos.

Tenemos tres clases, una de ellas es la mas importante, son ustedes mismos, los discípulos de esta respetable orden.  Esa clase tiene una relación de “Muchos a uno” con la clase Grado, y una relación de “Muchos a muchos” con la clase AyudaSocial.

Es decir, si sacamos una foto del sistema podemos afirmar:

  • Un discípulo puede tener relacionada tan solo un único grado, pero a un grado pueden pertenecer muchos discípulos.
  • Un discípulo puede brindar muchas ayudas sociales y una ayuda social puede estar impartida por muchos discípulos simultáneamente.

Segundo paso: Crear la estructura básica del modulo

Aquí deben aplicar los conocimientos que han construido anteriormente. Les va a quedar algo así:

Deben crear una carpeta con un nombre en minúsculas y sin espacios donde luego van a colocar los archivos del modulo. Esa carpeta será el modulo en sí, con todo su contenido.

Tercer paso: definimos el archivo de manifiesto

Esto también ya lo han visto, solo voy a mostrarles como ha quedado el mio.

# -*- coding: utf-8 -*-
{
    'name' : 'My first pythagorean module',
    'version' : '0.3',
    'summary': 'This a short description',
    'description': """
A larger description
====================
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In lobortis sodales ante non pulvinar. Ut maximus mi dui, ut luctus lectus tristique ut. Quisque at ligula nec nisl gravida imperdiet.
    """,
    'category': 'Project Management',
    'author': "My Company",
    'website': 'http://www.pythagoreanodoo.com',
    'depends' : [],
    'data': [],
    'installable': True,
    'auto_install': False,
}

En la siguiente imagen van a poder ver como se muestra la información del archivo manifiesto, en la interfaz web de odoo.

 

Cuatro paso: declarar los modelos

Dentro de la carpeta model vamos a crear los siguientes archivos python:

models/disciple.py

 
# -*- coding: utf-8 -*-
from odoo import models, fields

class Disciple(models.Model):
    _name   = 'pyth.disciple'

    name        = fields.Char(string="Full name")
    birthday    = fields.Datetime(string="Birthday")

    #Related fields
    degree_id           = fields.Many2one('pyth.dsple.degree',string="Degree")
    communityhelp_ids   = fields.Many2many(comodel_name='pyth.community.help',string="Comunity helps",
                                           relation="pyth_disciple_commhelp",
                                           column1="disciple_id",
                                           column2="commhelp_id")

La imagen que voy a colocar a continuación, es para ayudarlos a entender cómo resuelve Odoo las relaciones Many2many con los parámetros que ustedes le colocan en su declaración. Sepan que Odoo remplaza los puntos por guiones bajos para conformar el nombre de las tablas a partir del valor del parámetro _name.

Por lo general no es necesario que a las relaciones Many2many le coloquemos los parámetros relation, column1 y column2, Odoo lo resuelve solo, pero en este ejemplo los coloqué a propósito, para que entiendan desde un comienzo qué es lo que sucede. ¿Si Odoo lo resuelve solo para que sirven? Odoo para conformar el nombre de la tabla intermedia que sirve para relacionar de muchos a muchos, combina los dos nombres de las tablas que se relacionan y a veces, si los nombres de cada tabla son largos, al generar el nombre de la nueva tabla uniendo esos dos nombres, nos queda un nombre de tabla demasiado largo y Postgres se molesta y nos da error. Por eso Odoo nos da la posibilidad de ingresar el nombre de la tabla a mano, y el nombre de las columnas que identifican esa unión. Ya veremos enseguida, cómo se hace la declaración en el otro modelo (‘pyth.community.help’).

models/degree.py

# -*- coding: utf-8 -*-
from odoo import models, fields

class Degree(models.Model):
    _name   = 'pyth.dsple.degree'

    name        = fields.Char(string="Name")

    #inverse relation
    disciple_ids = fields.One2many('pyth.disciple',inverse_name='degree_id',string="Disciples")

Observen cómo este modelo declara un atributo de modelo llamado disciple_ids que será el encargado de guardar el valor relacional con el modelo Discípulo.

models/degree.py

 
# -*- coding: utf-8 -*-
from odoo import models, fields

class CommunityHelp(models.Model):
    _name   = 'pyth.community.help'

    name        = fields.Char(string="Name")
    description = fields.Html(string="Description")

    #related field
    disciple_ids   = fields.Many2many(comodel_name='pyth.disciple',string="Disciples",
                                           relation="pyth_disciple_commhelp",
                                           column1="commhelp_id",
                                           column2="disciple_id")

El atributo disciple_ids es el otro extremo de la relación Many2many que vimos en el modelo Disciple. Pongan atención en lo que sucedió con su declaración: el valor de column1 y column2 se invirtió, esto es porque estamos viendo la relación desde la otra orilla. Mientras que el valor del parámetro relation es el mismo, porque claramente hacemos referencia a la misma tabla auxiliar.

models/__init__.py

# -*- coding: utf-8 -*-

from . import degree,communityhelp,disciple

El archivo __init__.py importa todas las clases definidas en todos los archivos python que hemos declarados.

Ahora no debemos olvidarnos de algo muy importante: ir al archivo general __init__, el que está en la carpeta raíz del módulo e indicar que queremos importar todo lo que contiene la carpeta models.

__init__.py

# -*- coding: utf-8 -*-
from . import models

Alegría! Con eso hemos terminado de definir nuestros modelos de negocio. Ahora vamos a seguir con las vistas.

Quinto paso: La vista, action y menú  para nuestros modelos

Hagamos un minuto de silencio para que puedan agudizar sus sentidos, porque en esta etapa necesito que sean infalibles.

Dentro de la carpeta views, vamos a crear los siguientes archivos:

views/disciple_view.xml

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <data>
        <!--TREE VIEW-->
        <record id="view_disciple_tree" model="ir.ui.view">
            <field name="name">pyth.disciple.tree</field>
            <field name="model">pyth.disciple</field>
            <field name="arch" type="xml">
                <tree>
                    <field name="name"/>
                    <field name="birthday"/>
                    <field name="degree_id"/>
                </tree>
            </field>
        </record>

        <!-- FORM VIEW -->
        <record id="view_disciple_form" model="ir.ui.view">
            <field name="name">pyth.disciple.form</field>
            <field name="model">pyth.disciple</field>
            <field name="arch" type="xml">
                


<form string="Disciple">
                    <sheet>
                        <label for="name"/>
                       
<h1>
                            <field name="name"/>
                        </h1>

                        <group>
                            <field name="birthday"/>
                            <field name="degree_id"/>
                        </group>
                        <notebook>
                            <page string="Community helps">
                                <field name="communityhelp_ids"/>
                            </page>
                        </notebook>
                    </sheet>
                </form>



            </field>
        </record>

        <!-- ACTION -->
        <record model="ir.actions.act_window" id="pyth_disciple_action">
            <field name="name">Disciples</field>
            <field name="type">ir.actions.act_window</field>
            <field name="res_model">pyth.disciple</field>
            <field name="view_type">form</field>
            <field name="view_mode">tree,form</field>
            <field name="help" type="html">
                

<strong> Disciples</strong> list.
                

            </field>
        </record>

        <!-- MENUES -->
        <!-- MAIN menu -->
        <menuitem id="pyth_pythag_main" name="PythOdoo"/>

        <!-- Secondary menu -->
        <menuitem id="pyth_pythag_secondary_menu" name="Disciples" parent="pyth_pythag_main"/>

        <!-- Action disciple menu-->
        <menuitem id="pyth_disciple_submenu" name="Disciples" action="pyth_disciple_action" parent="pyth_pythag_secondary_menu"/>

    </data>
</odoo>

A fines de acelerar el proceso, en este mismo archivo he declarado el menú principal del modulo y un menú secundario. Ahora estamos aprendiendo y esto es tolerable, pero cuando sean mas grandes, coloquen cada cosa en su lugar, queda mas prolijo que coloquen el menú principal y los menúes secundarios en un solo archivo separado.

Como buena costumbre, cada vez que terminan de crear un archivo XML, vayan al archivo manifest y agréguenlo dentro del parámetro data , si no lo hacen el modulo odoo jamás se entera de su existencia. Quedaría así:

...
 'data': [
        'views/disciple_view.xml',
    ],
...

Nota: Es muy común olvidarse de poner la coma que separa los path de los archivos que declaramos en el parámetro ‘data’. Así que si se olvidan les va a dar un error que dice que no encuentra el path del archivo. 

Bueno, dentro de esta ventana modal voy a dejar el código para los otros dos archivos que nos falta crear, pero antes de copiar y pegar, les recomiendo que intenten hacerlo ustedes solos. No olviden agregar la ruta de los archivos nuevos en el manifest.

 

cerrar

Otra buena costumbre en Odoo, es ir probando el código a medida que avanzamos, porque es mas difícil encontrar los errores cuando ya tenemos todos los modelos y las vistas declarados.

Un momento, antes de seguir con el próximo post donde se explica como subir el código a nuestro servidor, reparemos algo importante.

  • Deben haber notado que los campos relacionales de nuestros modelos de negocio terminan en _id o _ids, bueno, desde luego que esto no es un capricho mío. Esto es una convención de Odoo, podrían no hacerlo y colocar el nombre que quieran, pero es recomendable hacerlo para que el código sea mas legible y también porque esos campos luego serán los nombres de las columnas de las tablas del modelo relacional y así queda fácil identificar que columnas son las relacionales.  En Resumen, la forma de diferenciar a simple vista los campos nativos del modelo y los campos relacionales, es agregándole el sufijo _id (Many2one) o _ids (One2many) a estos últimos.
  • También habrán notado que en ningún momento en la action, indicamos el ID de la vista tree y la vista form que hemos declarado. Esto es porque, cuando solo hay una vista form y una vista tree para cada modelo, Odoo asume que queremos mostrar esa. Mas adelante cuando tengamos mas de un tipo de vista para cada modelo, entonces veremos como se hace.

 

Ahora vamos a probar lo que tenemos hecho hasta este momento. Vayamos al próximo post.