14. Desarrollando con Odoo (9). Datos Demo. Conversión CSV a XML. Relaciones, imagenes y valores por defecto. Imagenes

 1. Introducción

En __manifest__.py aparece una referencia a los datos demo

    # only loaded in demonstration mode
    'demo': [
        'demo/demo.xml',
    ],

Y si vamos al fichero demo/demo.xml, este tiene datos pero comentados

Vamos a crear un registro de tipo developer en demo/xml llenando los campos imprescindibles

<record id="012DEV" model="res.partner">
    <field name="name">Desarrollador Demo</field>
    <field name="access_code">87654321ZZ</field>
    <field name="is_dev">True</field>
</record>

Si queremos generar datos aleatorios, podemos entrar en una web llamada Mockaroo, pero nos genera en formato csv, pero nos interesa tenerlo en xml

2. Conversión CSV a XML

Veamos un pequeño programa para convertir a xml este fichero csv:

1,Pepe 01, 11111111AA
2,Pepe 02, 21111111AA
3,Pepe 03, 31111111AA
4,Juan 01, 12111111AA
5,Juan 02, 12211111AA
6,Juan 03, 12311111AA
7,Maria 01, 13111111AA
8,Maria 02, 13211111AA
9,Maria 03, 13311111AA

Ahora hay que pasarle correctamente las rutas de los ficheros de entrada y salidfa. El programa es:

def csv2xml_developer(line):
    xml="""
    <record id='AYZ0$1$' model='res.partner'>
      <field name='name'>$1$</field>
      <field name='access_code'>$2$</field>
      <field name='is_dev'>True</field>
    </record>"""
    for i in range(len(line)):
        xml=xml.replace('$'+str(i)+'$',line[i].strip())
        print (xml)
    return xml

def developers_generator(source, dest_fname):
    with open(dest_fname, 'w') as out:
        out.write("<odoo>\n  <data>")
        with open(source, 'r') as inp:
            for line in inp:
                line=line.split(',')
                record=csv2xml_developer(line)
                out.write(record)
            inp.close()
        out.write("\n  </data>\n</odoo>")    
        out.close() 
    print('--------------------------')
    with open(dest_fname, 'r') as out:
        print (out.read())       

# main
mypath='/home/eduard/MyOdoo/Control-Presencia/my-python-programs/GTT/ODOO_IGIJON/ximoapp01'
developers_generator(mypath+'/demo/mockdata.csv',mypath+'/demo/mockdata.xml')

Ahora hay que ir a __manifest__.py e indicarle el fichero donde cargar los datos

    # only loaded in demonstration mode
    'demo': [
        'demo/demo.xml',
        'demo/mockdata.xml',
],

3. Añadir relaciones

3.1 Valor fijo

Cuando damos de alta los datos demo, vamos a obligar por modelo a asignar una category "Devs", para ello creamos una restricción del campo is_dev en el modelo "developer".

Recordar lo visto en una entrada anterior :

A la hora de buscar la categoría utilizamos self.env, y también a la hora de crearla.
                                                                                                                                              
Pero para asignar la categoria al campo tenemos que utilizar esta "argucia" (pues tenemos una relación many2many) donde asignamos al campo del modelo una lista de tuplas donde el 4 indica que el valor se va a modificar pero añadiendo a los valores que ya tenga un nuevo valor "category.id"

Veamos como queda el modelo

@api.constrains('is_dev')
def _check_is_dev(self):
  for record in self:
    if record.is_dev:
      categories = self.env['res.partner.category'].search([('name','=','Devs')])
      if len(categories)>0:
        category=categories[0]
      else:
        category = self.env['res.partner.category'].create({'name':'Devs'})   
      self.category_id=[4,category.id]


3.2 Campo relación many2one en XML -> ref

En el modelo "history" tenemos una relación Many2one a "project", y si sabemos el id de project podemos montar un xml de "history". Supongamos que el id de "project" es "PRJ_010", entonces el xml de "history" con el campo project referenciado "ref" a su "id":

<record id='HIS_001' model='ximoapp01.history'>
   <field name='name'>History 01</field>
   <field name='project' ref='PRJ_010'></field>
   <field name='is_dev'>True</field>
</record>
 

Por tanto podemos mejorar el programa anterior para que lea "projects" en CSV y los convierta a XML y de paso que haga lo mismo con "histories", pero referenciando el proyecto como hemos hecho antes

Y de paso hay que referenciar los ficheros generados en __manifest__.py 


3.3 Campo relación many2many en XML -> eval

En una relación many2many ya no os vale "ref". Tenemos que utilizar "eval" que recibe una lista de tuplas donde:
  • Se le indica el tipo de operación:  
    •     (0,_ ,{'field':value}) : Crea un nuevo registro y lo vincula
    •     (1,id,{'field':value}) : Actualiza los valores en un registro ya vinculado
    •     (2,id,_              ) : Desvincula y elimina el registro
    •     (3,id,_              ) : Desvincula pero no elimina el registro de la relación
    •     (4,id,_              ) : Vincula un registro ya existente
    •    (5,_ ,_              ) : Desvincula pero no elimina los registros vinculados
    •    (6,_ ,[ids]          ): Reemplaza la lista de registros vinculados
Como vemos en el trozo resaltado utilizamos la opción 6 de reemplazar los registros vinculados si los hubiera y los ids de los registros a vincular de la relación son "tech_1" y "tech_2"

<record id='dev:1' model='res.partner'>
  <field name='name'>Maria 03</field>
  <field name='access_code'>13311111AA</field>
  <field name='is_dev'>True</field>
  <field name='technologies' eval="[(6,0,[ref('tech_1')],[ref('tech_2')])]">True</field>
  <!-- 
    (0,_ ,{'field':value}) : Crea un nuevo registro y lo vincula
    (1,id,{'field':value}) : Actualiza los valores en un registro ya vinculado
    (2,id,_              ) : Desvincula y elimina el registro
    (3,id,_              ) : Desvincula pero no elimina el registro de la relación
    (4,id,_              ) : Vincula un registro ya existente
    (5,_ ,_              ) : Desvincula pero no elimina los registros vinculados
    (6,_ ,[ids]          ) : Reemplaza la lista de registros vinculados
  -->
</record>

Hay que tener en cuenta que en __manifest__.py se tiene que definir antes las technology.xml para que esten cargadas antes que los "developer" !!!

3.4 Campo calculado con eval

Podemos dar valor a un campo en xml utilizando eval .
OJO eval se asigna entre COMILLAS DOBLES.

<record id='dev:1' model='res.partner'>
      <field name='name'>Maria 03</field>
      <field name='access_code'>13311111AA</field>
      <field name='is_dev'>True</field>
      <field name='technologies' eval="[(6,0,[ref('technology_1')],[ref('technology_2')])]">True</field>
      <field name='last_login' eval="(datetime.now().strftime('Y%-%m-%d'))"></field>
    </record>


En este caso hemos asignado al campo "last_login" la fecha de ahora en formato YYYY-MM-DD

En una relación many2many ya no os vale "ref". Tenemos que utilizar "eval" que recibe una lista de tupl

3.5 Campo imagen

Nos tramos una carpeta de imagenes (myimages). Pero el valor del campo "technology.photo" es un fichero, por tante tenemos que convertir a Base64 y UTF-8 el contenido del fichero de la imagen.

Tenemos que abrir en python el fichero de la imagen y convertirlo en Base64 y luego generamos un string que será la línea del campo de la foto que escribimos al fichero de importacion xml

def prova(techName):
    image= open("myimages/"+techName+".png","rb")
    b64str=base64.b64encode(image.read()).decode('utf-8')
    write_text_to_file(f'<field name=\'photo\'>{b64str}</field>')


Y genera un xml muy largo pues guarda todo el contenido del fichero de imágenes en el xml

Para que se vea la miniatura de la imagen se le aplica en el form el widget "image" y para la miniatura se le aplica la clase "oe_avatar"

<field name="photo" widget="image" class="oe_avatar"/>


Comentarios

Entradas populares de este blog

4. Desarrollando con Odoo (2). Introducción a modulos, vistas, modelos .. Añadir dependencias externas de Python a Odoo

8. Desarrollando con Odoo (6). Herencia de clase en modelos. Herencia de vistas. Operaciones numeradas en Odoo ??

26. Desarrollando con Odoo (21). IMPORTANTE: Entorno de desarrollo. Recapitulaciones del capítulo 8 (Development, Test and Debug).