Sie sind auf Seite 1von 766

Odoo Desarrollo

Recetario

Complexión aplicaciones eficaces por aplicar Odoo


buenas prácticas de desarrollo

Holger Brunn
Alexandre Fayolle
Daniel Reis
BIRMINGHAM - MUMBAI
Odoo Recetario de desarrollo
Copyright © 2016 Packt Publishing

Todos los derechos reservaron. Ninguna parte de este libro puede ser reproducida,
almacenado en un retrieval sistema, o transmitido en cualquier forma o por cualquier medio,
sin el permiso escrito previo del editor, exceptúa en el caso de menciones breves embedded
en críticos unrticles o revisiones.
Cada esfuerzo ha sido hecho en la preparación de este libro para asegurar la exactitud de la
información presentó. Aun así, la información contenida en este libro está vendido sin
garantía, tampoco expresar o implicó. Tampoco los autores, no Packt Publicando, y sus
comerciantes y los distribuidores serán aguantados propensos para cualesquier daños
causados o alegados para ser causados directamente o indirectamente por este libro.
Packt La editorial ha intentado para proporcionar información de marca aproximadamente
todo de las compañías y products mencionó en este libro por el uso apropiado de capitales.
Aun así, Packt Publicando no puede garantizar la exactitud de esta información.

Primero publicó: April 2016

Referencia de producción: 1260416

Publicado por Packt Editorial Ltd.


Livery Sitio
35 Livery Calle
Birmingham B3 2PB,
Reino Unido.

ISBN 978-1-78588-364-4

www.packtpub.com
FM-2
Crédito
s

Autores Coordinador de
Holger Brunn proyecto
Kinjal Bari
Alexandre Fayolle
Daniel Reis
Proofreader
Safis Editando
Reviewers
Guewen Baconnier
Indexer
Stefan Rijnhart Monica Ajmera Mehta

Editor de adquisición Coordinador de


Manish Nainani producción
Arvindkumar Gupta
Editor de Desarrollo del
contenido
Trabajo de cubierta
Mehvash Fatima
Arvindkumar Gupta

Editores técnicos
Menza Mathew
Deepti Tuscano

Editores de copia
Merilyn Pereira
Alfa Singh
FM-3
Sobre los Autores
Holger Brunn Ha sido un código abierto ferviente defiende desde entonces entre para
contactar con el mercado de código abierto sometime en el nineties. Con un fondo
académico en filosofía y sociología, gire su interés a lógica generalizada, el cual prueba útil
en muchos aspectos de su trabaje. Convirtiendo en un programador profesional era un
efecto de lado de su hobbyist interest, combinado con una parte-trabajo de tiempo con un
muy abierto-mentor importado a quien debe mucho agradecimiento.
Ha programado para ERP y sistemas similares en posiciones diferentes desde entonces
2001. Para los últimos ocho años, ha dedicado su tiempo a TinyERP, el cual servino
OpenERP y evolucionado a Odoo. Actualmente, trabaja en Therp BV en el Netherlands como
desarrollador y es un miembro activo del Odoo Asociación Comunitaria (OCA). Es más
interesado en trabajo fundamental en módulos técnicos, pero también disfruta contributing a
otros proyectos, con un foco en UI y sitio web widgets, CRM, y administración de
conocimiento.

Alexandre Fayolle empezó trabajar con Linux y software libre en el mid 1990s y deprisa
se interesó en el lenguaje de programación de Pitón. Entre 1999 y 2012, ayude dirigir
Logilab, una compañía él cofounded, especialice en desarrollo de Pitón, y tuvo la
oportunidad de trabajar en proyectos para compañías grandes como EDF, Arcelor-Mittal, y
GdF Suez (ahora Engie) utilizando el Cubicweb marco.
Él también los proyectos divertidos emprendidos que implican aprendizaje de máquina,
procesamiento de lengua natural, y multi-sistemas de agente. En 2012, una Camptocamp
para compartir su pericia encima Pitón, PostgreSQL, y Linux con el equipo que implementa
Odoo (OpenERP en el tiempo). Él currently dirige proyectos para Camptocamp y es
fuertemente implicado en el Odoo Asociación Comunitaria. En su tiempo de sobra, le gusta
jugar el vibraphone en un cuarteto de jazz, pero recientemente ha sido sabido para escribir
un libro sobre Odoo, el cual espera que disfrutarás.
FM-4
Daniel Reis ha sido trabajando en el LO industria para encima 15 años en desarrollador,
asesor, y funciones de administración. La mayoría de este trabajo era en el Capgemini empresa
de asesoría de la multinacional, implementando soluciones empresariales propietarias para
reference compañías en una variedad de sectores, como industria, telecomunicaciones, y
amontonando. Daniel tiene un BSc en la matemática aplicada y un maestro es en
administración empresarial del ISCTE Escuela Empresarial.
Está trabajado con Odoo soluciones (anteriormente OpenERP) since 2010, y es un colaborador
activo en el Odoo proyectos de asociación comunitaria. Ha sido un hablante en el Abierto
Días conferencia anual y otros acontecimientos de código abierto. Es el autor del
primer Odoo libro de desarrollo: Odoo Desarrollo Essentials, también por Packt
Publicando.
Él actualmente trabajos en Securitas, la compañía de servicios de seguridad
global, donde ha introducido Pitón, Odoo, y otras soluciones de código abierto a la
compañía es carpeta de aplicaciones.

Doy las gracias a mi mujer, Maria José, para todoth e soporte y paciencia
que hizo este libro posible.
FM-5
Sobre el Reviewers
Guewen Baconnier Es un tipo discreto que no disfruta siendo puesto adelante. Trabaja en
Camptocamp donde está sido un TinyERP programamer antes de emotivo a OpenERP y ahora
Odoo. Es un entusiasta de software libre y un miembro activo del Odoo Asociación
Comunitaria (OCA), donde sus responsabilidades implican, entre otros, siendo el desarrollador
de ventaja del OCA Marco de Conector. Guewen También encanta libros así que tener que le
encuentras,
Hay una posibilidad buena pueda tener su nariz en uno, tampoco leyendo un libro técnico para
mantener arriba con su curiosidad ilimitada y hambre para aprender, o leyendo un novel a viaje en
algún fictional universo, o whatever el bien lee cayó a sus manos. Le gusta ir de excursión en el
campo con su mujer amada. Es también el padre feliz de dos niños buenos, con quien disfruta
gastar tiempo, paseando, yendo a la biblioteca, leyendo libros, y jugando Kerbal Programa
Espacial.

Me gustaría dar las gracias a mi mujer y niños para de apoyo mío tiredness
en el morrows de anocheceres largos de revisar. Y me gustaría dar las gracias
a Alexandre Fayolle quién me ayudé forma esta biografía corta. Finalmente,
gracias a mis colegas y a todo contributors del OCA de quien aprendo todos
los días.

Stefan Rijnhart es una vida-el código abierto largo defiende y ha sido un tiempo lleno
Odoo asesor y desarrollador desde entonces 2010. Disfruta colaborar en el Odoo
Comunidad
Asociación (OCA), el cual encuentra para ser mutuamente beneficioso a sus clientes'
proyectos. En el
OCA, Stefan jugó una función clave en la creación del OpenUpgrade proyecto de migración
para Odoo y en el Odoo Comunitario Backports proyecto (OCB). Off-line, le puedes encontrar
montando una bicicleta cargadora through las calles de Amsterdam con su hijo en el asiento
de frente, o jugando música con su banda. Entra tacto con Stefan en
http://abridor.amsterdam.
FM-6
www.packtpub.com

eBooks, ofertas de descuento, und más


Sabes que Packt ofrece eBook las versiones de cada libro publicaron, con PDF y ePub
archiva disponible? Puedes upgrade al eBook versión en www.packtpub.com y como
cliente de libro de la impresión, estás titulado a un descuento en el eBook copia. Entra
tacto con nosotros en customercare@packtpub.com para más detalles.
En www.packtpub.com, puedes también leído una colección de artículos técnicos libres,
señal arriba para una gama de libre newsletters y receive ofertas y descuentos exclusivos
en Packt libros y eBooks.
TM

https://www2.packtpub.com/books/subscription/packtlib

Necesitas soluciones de instante a vuestro cuestiona? PacktLib Es Packt biblioteca de


libro digital on-line. Aquí, puedes buscar, acceso, y leer Packt biblioteca entera de libros.

Por qué suscribe?


f Plenamente searchable a través de cada libro
f publicado por Packt Copia y pasta, impresión, y
f contenido de marcapáginas
Encima demanda y accesible vía un navegador de
web
FM-7
Mesa de Contenidos
Prefacio vii
Capítulo 1: Instalando el Odoo Entorno de Desarrollo 1
Introducción 1
Instalación fácil de Odoo de fuente 2
Gestor Odoo los entornos que utilizan el storden de arte 9
Gestor Odoo bases de datos de servidor 10
Almacenando la configuración de caso en un archivo 19
Activando el Odoo herramientas de desarrollador 22
Actualizando Odoo de fuente 25
Capítulo 2: Gestor Odoo Casos de Servidor 29
Introducción 29
Configurando el addons path 30
Actualizando el addon lista de módulos 31
Estandarizando vuestro diseño de directorio del caso 33
Instalando y upgrading local addon módulos 36
Instalando addon módulos de GitHub 40
Aplicando cambios a addons 42
Aplicando y probando peticiones de atracción propuesta 43
Capítulo 3: Creando Odoo Módulos 47
Introducción 47
Creando e instalando un nuevo addon módulo 48
Completando el addon el módulo manifiesta 49
Organizando el addon estructura de archivo del módulo 52
Añadiendo modelos 55
Añadiendo Elementos de Carta y Vistas 57
Utilizando scaffold para crear un módulo 61

i
Mesa de Contenidos
Capítulo 4: Modelos de Aplicación 63
Introducción 63
Definiendo la representación de Modelo y orden 64
Añadiendo campos de dato a un modelo 66
Utilizando un campo de flotador con configurable precisión 71
Añadiendo unmo netary campo a un Modelo 73
Añadiendo campos relacionales a un Modelo 74
Añadiendo una jerarquía a un Modelo 78
Añadiendo validaciones de constreñimiento a un Modelo 80
Añadiendo computó campos a un Modelo 82
Exponiendo Relacionó los campos almacenaron en otros modelos 85
Añadiendo dinámico relatlos iones que utilizan campos de Referencia 86
Añadiendo características a un Modelo que utiliza herencia 87
Utilizando Modelos Abstractos para características de Modelo
reutilizable 89
Utilizando herencia de Delegación para copiar características a otro
Modelo 91
Capítulo 5: Desarrollo de Lado de Servidor Básico 95
Introduction 95
Definiendo métodos de modelo y utilizar el API decorators 96
Informando errores al usuario 99
Obteniendo un vacío recordset para un modelo diferente 101
Creando registros nuevos 102
Actualizando valores de recordset registros 104
Buscando registros 107
Combinando recordsets 109
Filtrando recordsets 110
Traversing recordset Relaciones 112
Extendiendo la lógica empresarial definida en un Modelo 114
Extendiendo escribe() y crear() 117
Personalizando cómo los registros están buscados 120
Capítulo 6: Desarrollo de Lado de Servidor Adelantado
Techniques 125
Introducción 125
Cambio el usuario que actúa una acción 126
Llamada un método con un contexto modificado 128
Ejecuta consultas de SQL crudo 130
Escribir un brujo para guiar el usuario 133
Define onchange métodos 138
Llamada onchange métodos en el lado de servidor 141
Portuario viejo API código al nuevo API 143
ii
Mesa de
Contenidos
Capítulo 7: Depuración y Testaje Automatizado 153
Introducción 153
Produciendo registros de servidor para ayudar depurar métodos 153
Utilizando el Odoo concha a interactivamente métodos de
llamada 157
Utilizando el depurador de Pitón para localizar ejecución de
método 159
Escribiendo pruebas para vuestro módulo que utiliza YAML 164
Escribiendo pruebas para vuestro módulo que utiliza pruebas de
unidad de la Pitón 168
Corriendo pruebas de servidor 172
Utilizando el Odoo Asociación Comunitaria maintainer quality
herramientas 173
Capítulo 8: Backend Vistas 179
Introducción 180
Añadiendo un elemento de carta y acción de ventana 180
Teniendo una acción abre una vista concreta 184
Añadiendo contenido y widgets a una vista de forma 186
Añadiendo botones a formas 189
Pasando parámetros a formas y acciones: Contexto 190
Definiendo filtros oficialmente listas: Ámbito 193
Vistas de lista 196
Vistas de búsqueda 198
Cambiando existiendo vistas: herencia de Vista 201
Documento-formas de estilo 205
Elementos de forma dinámica que utilizan attrs 207
Embedded Vistas 207
Kanban Vistas 209
Espectáculo kanban tarjetas en columnas según su estado 211
Vistas de calendario 212
Graph Y vistas de pivote 213
QWeb Informes 215
Capítulo 9: Dato de Módulo 219
Introducción 219
Utilizando externo IDs y namespaces 219
Cargando data utilizando XML archivos 221
Utilizando el noupdate y forcecreate banderas 224
Cargando el dato que utiliza CSV archivos 226
Cargando el dato que utiliza YAML archivos 228
Addon Actualizaciones y migración de dato 229
Capítulo 10: Seguridad de Acceso 233
Crea grupos de seguridad y asignarles a usuarios 233
Añade acceso de seguridad a modelos 238

iii
Mesa de
Contenidos
Acceso de límite a campos en modelos 241
Límite el acceso récord que utiliza reglas récord 243
Utilizando grupo de seguridad para activar características 246
Capítulo 11: Internationalizatión 253
Instalando una lengua y configurar preferencias de usuario 253
Configura lengua-relacionó encuadres 257
Traduce textos a través de la interfaz de usuario de cliente de
web 258
Cuerdas de traducción exportadora a un archivo 261
Uso gettext herramientas para aliviar traducciones 264
Archivos de traducción de la importación 266
Capítulo 12: Automatización y Workflows 269
Introducción 269
Utilizando Kanban etapas y características 270
Creando acciones de servidor 273
Añadiendo messaging y siguiendo características 276
Utilizando acciones de servidor de código de Pitón 281
Utilizando automatizado unctions puntualmente condiciones 283
Utilizando automatizó acciones encima condiciones de
acontecimiento 288
Inspeccionando construido-en workflows 291
Capítulo 13: Desarrollo de Servidor de la Web 295
Introducción 295
Marca un camino accesible de la red 295
Restringe acceso a web camino accesibles 300
Consume los parámetros pasaron a vuestro handlers 302
Modificar un existiendo handler 304
Utilizando el RPC API 307
Capítulo 14: Desarrollo de Sitio web del CMS 311
Introducción 311
Extendiendo CSS y Javascript para el sitio web 311
Creando o modificando plantillas - QWeb 314
Ofreciendo fragmento al usuario 318
Capítulo 15: Desarrollo de Cliente de la Web 325
Introducción 325
Creando hecho de encargo widgets 325
Utilizando cliente-lado QWeb plantillas 331
Haciendo RPC llamadas al servidor 333
Escribiendo pruebas para código de lado del cliente 336
Depurándoter código de lado del cliente 340
iv
Mesa de
Contenidos
Capítulo 16: Despliegue de Servidor 345
Introducción 345
Instalando Odoo para producción 345
Adaptando el archivo de configuración para producción 351
Instalado Odoo como servicio de sistema 355
Configure Un inverso proxy y SSL 357
Uso buildout para repeatable complexiones 362
Índice 371

v
Prefacio
Odoo, anteriormente sabido cuando OpenERP, es una plataforma grande para
desarrolladores. El marco en su core es muy rico y deja construir cliente–aplicaciones de
servidor de tachar así como adaptando existiendo aplicaciones a vuestras necesidades a
través de un mecanismo de extensión listo y un diseño muy modular. Las versiones más
tardías han traído una riqueza de nuevo possibilities con la adición de un lleno-desarrollo
de sitio web presentado stack. El alcance es enorme y es fácil para recién llegados para
sentir perdidos.
Para años, Odoo los desarrolladores han sido aprendiendo su oficio por leer el código del addon
módulos, los cuales están construidos arriba de the marco para proporcionar características de
administración de la empresa.
Mientras eficaz, el proceso es mucho tiempo y error prone, desde entonces es difícil de saber si el
código de fuente estás aprendiendo de está utilizando las posibilidades más tardías ofrecieron por
el marco, o si estás mirando en un módulo más viejo aquello no ha sido actualizado para utilizar
estas características. Para hacer las cosas peores, algunos flujos de código son intrínsecamente
duros de seguir porque son en parte en la capa de lógica empresarial, en parte en la capa de base
de datos, en parte en la petición handling capa, y en parte en el código de lado del cliente. La
introducción de un nuevo API en versión 8 tiene hizo cosas aún más confundiendo, desde entonces
la mayoría de la base de código no fue inmediatamente ported a este nuevo API.
Este libro está significado para salvarte tiempo por tocar en a los años de experimentar
acumulado por largo-cronometrar Odoo colaboradores para aprender las buenas prácticas
actuales en Odoo desarrollo por centrar en las características nuevas de versión 9, y también
dando una base sólida en el existiendo funcionalidad madura del marco. Since Odoo Tiene una
tradición larga de garantizar backward compatibilidad, la mayoría del material presentado tiene
que todavía trabajo con el upcoming versiones.

Qué estas cubiertas de libro


Este libro contiene 16 capítulos. Probamos duros de hacer cada capítulo como
independiente como posible, y para hacer las varias recetas en cada capítulo self-
contuvo.
Capítulo 1, Instalando el Odoo Entorno de Desarrollo, explica cómo para crear un
entorno de desarrollo para Odoo, inicio Odoo, crear un archivo de configuración, y
activar el desarrollarer herramientas de Odoo.

vii
Prefacio

Capítulo 2, Dirigiendo Odoo Casos de Servidor, es sobre addon instalación y upgrading.


Proporciona consejos útiles para laborables con addons instalados de GitHub, y
organizando el código de fuente de vuestro caso.
Capítulo 3, Creando Odoo Módulos, explica la estructura de un Odoo addon módulo y da
un paso-por-guía de paso para crear un módulo sencillo de arañazo.
Capítulo 4, Modelos de Aplicación, foco en Odoo descripciones de modelo, y explica los
varios tipos de campo y los modelos de herencia diferentes disponibles en Odoo.
Capítulo 5, Desarrollo de Lado de Servidor Básico, introduce el v8 API de Odoo, presenta el
generalmente utilizó métodos de la clase de Modelo, y explica cómo para escribir métodos de
lógica empresarial.
Capítulo 6, Adelantado Server Técnicas de Desarrollo del Lado, trata más adelantó los temas
útiles cuándo escribiendo métodos empresariales como escribir brujos para andar el usuario a
través de un proceso o escribiendo onchange métodos. También cubre porting código del viejo
API al
v8 API.

Chapter 7, Depurando y Testaje Automatizado, propone algunas estrategias para


servidor-depuración de lado y una introducción al depurador de Pitón. También explica
cómo para escribir y correr automatizado prueba utilizar YAML o Pitón para vuestro
addon módulos.
Capítulo 8, Backend Views, explica cómo para escribir vistas empresariales para vuestros
modelos de dato y cómo para llamar servidor-métodos de lado de estas vistas. Cubre las
vistas habituales (vista de lista, vista de forma, y vista de búsqueda) así como las vistas
introdujeron en versiones recientes de Odoo (Kanban, graph, calendario, pivote, y tan
encima)
Capítulo 9, Dato de Módulo, espectáculos cómo para embarcar dato junto con el código de
vuestro módulo. También explica cómo para escribir un guión de migración cuándo un
modelo de dato proporcionado por un addon está modificado en una liberación nueva.
Capítulo 10, Acceso Security, explica cómo para controlar quién tiene acceso a qué en
vuestro Odoo caso, por crear grupos de seguridad, escribiendo listas de control del acceso
para definir lo que las operaciones son disponibles a cada grupo en un modelo dado, y, si es
necesario, por escribir reglas de nivel récord.
Capítulo 11, Internacionalización, trata la traducción de las interfaces de usuario de vuestro
addons.

Capítulo 12, Automatización y Workflows, ilustra las herramientas diferentes disponibles en


Odoo para implementar proceso empresarial para vuestros registros. También muestra qué
acciones de servidor y automatizó las reglas pueden soler soporte reglas empresariales.
Capítulo 13, Desarrollo de Servidor de la Web, trata el núcleo del servidor de web en Odoo.
Explica cómo a mapa URLs a métodos y cómo para controlar quiénes pueden acceder
estos URLs.
Capítulo 14, Desarrollo de Sitio web del CMS, espectáculos cómo para personalizar los sitios
web construyeron con Odoo, por escribir vuestras plantillas propias y proporcionando
fragmento nuevas para uso en el constructor de sitio web.

viii
Prefacio

Capítulo 15, Desarrollo de Cliente de la Web, zambullimientos a la parte de Javascript de


Odoo y explica cómo puedes proporcionar nuevo widgets y hacer RPC llamadas al
servidor. También da consejos aproximadamente depurando y probando esta parte de
vuestro código.
Capítulo 16, Despliegue de Servidor, proporciona consejo encima cómo para instalar y
configurar Odoo para productiencima, incluyendo instalando un inverso proxy para
encriptar comunicaciones de red encima HTTPS y asegurando que Odoo inicios cuándo
las botas de servidor.

Quién este libro es para


Este libro está apuntado en desarrolladores de Pitón que quieren aprender Odoo desarrollo o
consolidar su Odoo habilidades. Alguna experiencia con el lenguaje de programación de
Javascript y desarrollo de web en general está requerido a plenamente beneficio del frontend
capítulos.

Este foco de libro encima desarrollo de aplicación del núcleo. No cubre cómo para utilizar el
business las aplicaciones proporcionadas por Odoo. Puedes querer referir a Trabajar con
Odoo, por Greg Musgo, para este.
Este libro no proporciona explicaciones aproximadamente cómo el internals del trabajo de
aplicaciones de administración de empresa. Para entender esto, tendrás que leer el código
de fuente y experimento para tú. Siendo familiar con los contenidos del Odoo Recetario de
Desarrollo tendría que hacer vuestra vida más fácil, cuando contiene punteros a partes del
código puedes leer para aprender sobre un tema concreto.

Qué necesitas para este libro


El instalar recetas en Capítulo 1, Instalando el Odoo Entorno de Desarrollo, y Capítulo 15,
Desarrollo de Cliente de la web, espera que estás trabajando en un servidor que corre Debian
GNU/Linux, o una distribución derivada como Ubuntu, en un razonablemente arriba-a-liberación
de fecha. Si estás corriendo otra distribución, las cosas tendrían que ser bastante sinceras; las
diferencias principales tendrían que ser
En los nombres de los paquetes para instalar, y posiblemente la ubicación de los archivos de
configuración de
PostgreSQL Y Nginx.

Siy nuestro workstation está corriendo Windows o MacOS, te aconsejáis para instalar un Debian
máquina virtual para trabajar con Odoo. Mientras es posible de desarrollar natively encima
Windows o Mac, habiendo un entorno de desarrollo como cercano como posible al entorno de
despliegue es una manera buena de evitar sorpresas malas y GNU/Linux es la plataforma de
despliegue recomendable para Odoo.
ix
Prefacio

Es allí un Entorno de Desarrollo Integrado recomendable (IDE) para Odoo? Esto es una
cuestión frecuentemente preguntada por recién llegados. La respuesta mejor es para
utilizar cualquier herramienta eres familiar con. Las elecciones populares incluyen Eclipse
o PyCharm, pero un número muy alto de experimented desarrolladores, incluyendo el
núcleo Odoo desarrolladores, uso justo un editor de texto de la programación como vim,
GNU emacs, or Texto Sublime para tener la sintaxis que destaca y útil helpers como sangría
automática, mientras utilizando el depurador de Pitón para depurar. Está recomendado
para empezar las herramientas básicas porque IDEs tener una tendencia para esconder
complejidad tendrías que ser familiar con para fijar los problemas más duros.

Secciones
En este libro, encontrarás muchos headings aquello aparece frecuentemente (Preparándose,
Cómo para hacerlo,
Cómo trabaja, Allí ha más, y Ver también).

Para dar instrucciones claras encima cómo para completar una receta, utilizamos estas
secciones como sigue:

Preparándose
Esta sección te dices qué para esperar en la receta, y describe cómo para instalar cualquier
software o cualesquier encuadres preliminares requirieron para la receta.

Cómo para hacerlo…


Esta sección contiene los pasos requirieron para seguir la receta.

Cómo trabaja…
Esta sección normalmente consta de una explicación detallada de qué pasado en la sección
anterior.

Allí ha más…
Esta sección consta de información adicional sobre la receta para hacer el lector más
sabeledgeable sobre la receta.

Ve también
Esta sección proporciona enlaces útiles a otra información útil para la receta.
x
Prefacio

Convenciones
En este libro, encontrarás un número de estilos de texto que distingue entre clases diferentes
of información. Aquí es algunos ejemplos de estos estilos y una explicación de su significado.
Palabras de código en texto, nombres de mesa de la base de datos, nombres de carpeta,
filenames, extensiones de archivo, pathnames, dummy URLs, entrada de usuario, y mangos
de Twitter están mostrados como sigue: "The parsing del archivo de configuración por Odoo
está hecho utilizando la Pitón ConfigParser módulo."
Un bloque de código está puesto como sigue:

[DEFAULT]
Casa = /de
proyecto/odoo/proyecta/proyecto1 env =
dev
Prefijo = %(proyecto)s/%(env)s

[Opciones]
addons-Camino =
%(prefijo)s/odoo/addons,%(prefijo)s/OCA/servidor-dato de
herramientas_dir = %(prefijo)s/dato_dir

Cuándo deseamos dibujar vuestra atención a una parte particular de un bloque de código,
las líneas pertinentes o los elementos están puestos en negrita:
{ 'Nombre': 'Capítulo 03 código',
'Depende': ['base', 'decimal_precision],
'Dato': ['libro/de biblioteca_de las vistas.xml'] }

Cualquier orden-entrada de línea o la producción está escrita como sigue:

$ sudo Apto-conseguir instalar git pitón2.7 postgresql nano pitón-


virtualenv

Los plazos nuevos y las palabras importantes están mostrados en negrita. Palabras que
ves en la pantalla, por ejemplo, en cartas o cajas de diálogo, aparece en el texto así: "Clic
en el Dirigir enlace de Bases de datos."

Los avisos o las notas importantes aparecen en una caja así.

Los consejos y los trucos aparecen así.


xi
Prefacio

Retroalimentación de lector
Feedback De nuestros lectores es siempre bienvenidos. Dejado nos saber qué piensas
sobre este reservar— qué te gustó o desagradó. Retroalimentación de lector es importante
para nosotros tan nos ayudo desarrollar títulos que te realmente conseguirá el más fuera
de.
Para enviarnos retroalimentación general, simemail de chapa
feedback@packtpub.com, y mencionar el título del libro en el tema de vuestro
mensaje.
Si hay un tema que tienes pericia en y estás interesado en cualquier escritura o
contribuyendo a un libro, ver nuestra guía de autor en
www.packtpub.com/authors.

Soporte de cliente
Ahora que eres el dueño orgulloso de un Packt libro, tenemos un número de cosas para
ayudarte para conseguir el más de vuestra compra.

Descargando el código de ejemplo


Puedes descargar los archivos de código del ejemplo para este libro de vuestra cuenta en
http://www. packtpub.com. Si adquiriste este libro en otro lugar, puedes visitar
http://www.packtpub. com/Soporte y registro para tener los archivos e-mailed
directamente a ti.
Puedes descargar los archivos de código por siguientes estos pasos:

1. Registro en o registro a nuestro sitio web que utiliza vuestra dirección de email y
password.
2. Cercar el puntero de ratón en el tabulador de SOPORTE en la parte superior.
3. Clic encima Descargas de Código & Errata.
4. Introducir el nombre del libro en la caja de Búsqueda.
5. Seleccionar el libro para qué estás mirando para descargar los archivos de código.
6. Escoge de la gota-abajo carta donde you adquirió este libro de.
7. Clic encima Descarga de Código.

También puedes descargar los archivos de código por clicking en el botón de Archivos del
Código en la página web del libro en el Packt sitio web Editorial. Esta página puede ser accedida
por introducir el nombre del libro en la caja de Búsqueda. Complacer nota que necesitas ser
logged en a vuestro Packt cuenta.
xii
Prefacio

Una vez el archivo está descargado, complacer marca seguro que te unzip o extraer la
carpeta que utiliza la versión más tardía de:
f WinRAR / 7-Cremallera para
f Windows Zipeg / iZip /
f UnRarX para Mac 7-
Cremallera / PeaZip para
Linux

Descargando las imágenes de color de este libro


También proporcionamos tú con un PDF archivas aquello tiene imágenes de color del
screenshots/los esquemas utilizaron en este libro. Las imágenes de color te ayudarán mejores
entender el changes en la producción.
Puedes descargar este archivo de http://www.packtpub.com/sites/default/files/
descargas/Bookname_ColorImages.Pdf.

Errata
A pesar de que hemos tomado cada cuidado para asegurar la exactitud de nuestro contenido,
las equivocaciones pasan. Si encuentras una equivocación en uno de nuestros libros—quizás
una equivocación en el texto o el código— seríamos agradecidos si podrías informar esto a
nosotros. Por hacer tan, puedes salvar otros lectores de frustración y ayudarnos mejorar
versiones subsiguientes de este libro. Si encuentras cualquier errata, complacer informarles por
visitar http://www.packtpub.com/submit-errata, seleccionando vuestro libro, clicking en
el Errata enlace de Forma de la Sumisión, e introduciendo los detalles de vuestro errata. Una
vez vuestro errata está verificado, vuestra sumisión será aceptada y el errata
Ser cargado a nuestro sitio web o añadido a cualquier lista de existir errata bajo el Errata
sección de aquel título.
Para ver el anteriormente entregado errata, va a https://www.packtpub.com/books/
soporte/de contenido e introducir el nombre del libro en el campo de búsqueda. La
información requerida aparecerá bajo el Errata sección.

Piratería
Piratería de copyrighted el material en el Internet es un problema actual a través de todos
los medios de comunicación. En Packt, tomamos la protección de nuestro copyright y
autoriza muy seriamente. Si encuentras cualesquier copias ilegales de nuestros trabajos en
cualquier forma en el Internet, complacer proporcionarnos con la dirección de ubicación o
nombre de sitio web inmediatamente de modo que podemos perseguir un remedio.
Complacer contactarnos en copyright@packtpub.com con un enlace al sospechó material
pirateado.
Apreciamos vuestra ayuda en proteger nuestros autores y nuestra capacidad de traerte contenido
valioso.

xiii
Prefacio

Cuestiones
Si tienes un problema con cualquier aspecto de este libro, nos puedes contactar
en questions@packtpub.com, y haremos nuestro mejores de dirigir el
problema.

xiv
1
Instalando el
Odoo Desarrollo
Entorno
En este capítulo, cubriremos los temas siguientes:

f Instalación fácil de Odoo de fuente


fGestor Odoo los entornos que utilizan la ordende
iniciofDirigiendo Odoo bases de datos de servidor
f Almacenando la configuración de caso en un archivo
fActivando el Odoo herramientas de
desarrolladorfActualizando Odoo
de fuente

Introducción
Hay muchas maneras de instalar un Odoo entorno de desarrollo. Este capítulo propone uno
de estos, a pesar de que ciertamente encontrarás un número de otro tutorials en la web que
explica otro approaches. Mantiene en importar que este capítulo es sobre un entorno de
desarrollo, el cual tiene requisitos diferentes de un entorno de producción, cubierto en
Capítulo 16, Despliegue de Servidor.
1
Instalando el Odoo Entorno de Desarrollo

Fácil installation de Odoo de fuente


Para Odoo despliegue, está recomendado para utilizar un GNU/entorno de Linux.
Puedes ser más en alivia utilizar Windows de Microsoft o Mac OS X, pero el hecho es
que la mayoría del Odoo los desarrolladores están utilizando GNU/Linux y tú son mucho
más likely para conseguir soporte de la comunidad para OS-el nivel emite pasar en
GNU/Linux que encima Windows.
Es también recomendado para desarrollar utilizando el mismo entorno (distribución misma,
versión misma) cuando el que será utilizado en producción. Esto evitará sorpresas malas
como descubrir en el día de despliegue que alguna biblioteca tiene una versión diferente que
esperado, con un comportamiento ligeramente diferente e incompatible. Si vuestro
workstation está utilizando un diferente OS, una aproximación buena es para instalar un
virtual machine en vuestro workstation y para instalar un GNU/distribución de Linux en el
VM.

Para evitar copiando archivos entre vuestro workstation donde estás


corriendo vuestro entorno de desarrollo y la máquina virtual qué carreras
Odoo, puedes configurar un SAMBA participación inside la máquina
virtual y almacenar el código de fuente allí. Entonces puedes montar la
participación en vuestro workstation para editar los archivos fácilmente.

Este libro supone estás corriendo Debian GNU/Linux como su versión estable (Jessie en el
tiempo de escribir). Ubuntu is Otra elección popular, y desde entonces está construido arriba
de Debian, la mayoría de los ejemplos en este libro tendrían que trabajar sin cambios.
Cualquier distribución de Linux escoges, tendrías que tener alguna idea de cómo para
utilizar él de la línea de orden, y teniendo unas cuantas ideas abfuera administración de
sistema ciertamente no causa cualquier daño.

Preparándose
Suponemos aquel Linux es arriba y corriendo y que tienes una cuenta con acceso de raíz,
tampoco porque sabes la contraseña de raíz o porque sudo ha sido configurado. En el
seguiring páginas, seremos utilizar $(whoami) siempre que el login de vuestro usuario de
trabajo está requerido en una línea de orden. Esto es una concha manda cuál sustituirá
vuestro login en la orden estás escribiendo.
Algunas operaciones sin duda serán más fáciles si tienes un GitHub
cuenta. Va a https://github.com y crear uno si no tienes uno ya.

Cómo para hacerlo...


Para instalar Odoo de fuente, necesitas seguir estos pasos:

1. Corrido las órdenes siguientes para instalar el principales dependencies:


$ sudo Apto-conseguir instalar git pitón2.7 postgresql
nano \ pitón-virtualenv
2
Capítulo 1

2. Descarga e instalar wkhtmltopdf:


$ wget http://nightly.odoo.com/extra/wkhtmltox-0.12.1.2_linux-
jessie-amd64.deb
$ sudo dpkg -i wkhtmltox-0.12.1.2_linux-jessie-amd64.deb

Amonestación!
Esto es un paquete proporcionado por el Odoo maintainer para
Debian Jessie. Si estás utilizando otra distribución, explora a
http://descarga. gna.org/wkhtmltopdf/0.12/0.12.1/ Y
descargar el paquete para vuestro sistema operativo.

3. Ahora, uso esto para instalar las dependencias de complexión:


$ sudo Apto-conseguir instalar gcc pitón2.7-dev libxml2-dev \
libxslt1-dev libevent-dev libsasl2-dev libldap2-dev libpq-dev
\ libpng12-dev libjpeg-dev

4. Configura PostgreSQL:
$ sudo -u postgres createuser --createdb $(whoami)
$ createdb $(whoami)

5. Configura git:
$ git config --Global user.name "Vuestro Nombre"
$ git config --Usuario global.Email youremail@example.com

6. Clonar el Odoo base de


código: $ mkdir ~/odoo-
dev
$ cd ~/odoo-dev
$ git Clon -b 9.0 --solo-rama https://github.com/odoo/odoo. git
$ cd odoo

7. Crear un odoo-9.0 entorno virtual y activarlo: $


virtualenv ~/odoo-9.0
$ Fuente ~/odoo-9.0/cubo/activa

8. Instalar las dependencias de Pitón de Odoo en


virtualenv: $ pip instalar -r requisitos.txt

3
Instalando el Odoo Entorno de Desarrollo

9. Crea y empezar vuestro primer Odoo


casos: $ createdb odoo-prueba
$ Pitón odoo.py -d odoo-Prueba --addons-camino=addons
\ --dbfilter=odoo-probar$

10. Punto vuestro navegador a http://localhost:8069 y autenticar utilizando el admin


cuenta y admin tan contraseña.

Puedes descargar los archivos de código del ejemplo para este libro de
vuestra cuenta en http://www.packtpub.com. Si adquiriste este
libro en otro lugar, puedes visitar
http://www.packtpub.com/support y registro para tener los
archivos e-mailed directamente a ti.
Puedes descargar los archivos de código por siguientes estos pasos:
fRegistro en o registro a nuestro sitio web que utiliza vuestra
dirección de email y contraseña
fCerca el puntero de ratón entabuladorde

SOPORTE en el superiorfClic encimaDescargas de


Código & Errata
f Introduce el nombre del libro enth e caja de Búsqueda
f Selecciona el libro para qué estás mirando para descargar los archivos de
código
fEscoge de la gota-abajo carta donde adquiriste este librode
f Clic encima Descarga de Código
También puedes descargar los archivos de código por clicking en el botón
de Archivos del Código en la página web del libro en el Packt sitio web
Editorial. Esta página puede ser accedida por introducir el nombre del libro
en la caja de Búsqueda. Complacer nota que necesitas ser logged en a
vuestro Packt cuenta.
Una vez el archivo está descargado, complacer marca seguro que te unzip
o extraer la carpeta que utiliza la versión más tardía de:
fWinRAR / 7-Cremallera para

WindowsfZipeg / iZip /
UnRarX para Macf7-
Cremallera / PeaZip para Linux

Cómo trabaja...
Las dependencias provienen varias fuentes. Primero, tienes las dependencias de núcleo
de Odoo, el Pythencima intérprete que suele corrido el código de fuente, y el PostgreSQL
servidor de base de datos utilizó para almacenar el dato de caso. Git Está utilizado para
código de fuente versioning y consiguiendo el código de fuente de Odoo él.
4
Capítulo 1

Desde entonces necesitaremos editar algunos archiva tan raíz o cuando postgres (el
PostgreSQL usuario administrativo) en nuestro servidor, necesitamos instalar una consola-
editor de texto basado. Sugerimos nano cuando es muy sencillo de utilizar, pero sentir libre
de escoger cualquier editor con qué sientes en aliviar mientras trabaja en la consola, como
vim, e3, o emacs-nox .
Wkhtmltopdf Es un runtime dependencia de Odoo utilizó para producir informes de PDF. La
versión requerida por Odoo 9.0 es 0.12.1, el cual no es incluido en actual GNU/distribuciones de
Linux. Afortunadamente para nosotros, el maintainers de wkhtmltopdf proporcionar prebuilt
paquetes para varias distribuciones en http://wkhtmltopdf.org/downloads.html (en la
sección de archivo). Aun así, Debian Jessie no es allí, así que el Odoo maintainers proporciona su
versión propia del
Paquete en http://nightly.odoo.com/extra/.
hay mucho otro runtime dependencias que es módulos de Pitón, el cual podemos instalar
utilizar pip en un entorno virtual. However, algunos de estos módulos de Pitón pueden
presentar algunas dependencias en nativos C bibliotecas para qué las encuadernaciones
de Pitón necesidad de ser compilada. Por tanto instalamos los paquetes de desarrollo para
estas C bibliotecas así como el paquete de desarrollo de la Pitón y un C compilador. Una
vez estas dependencias de complexión están instaladas, podemos utilizar pip -r
requisitos.txt (Un archivar cuál proviene el Odoo distribución de código de la fuente)
para descargar, compila, e instalar los módulos de Pitón.

Entornos virtuales
Pitón entornos virtuales, o virtualenv para cortos, es Pitón aislada workspaces. Son muy útiles a
desarrolladores de Pitón porque dejan diferentes workspaces con versiones diferentes de varias
bibliotecas de Pitón instaladas, posiblemente en versiones de intérprete de Pitón diferentes.

You Puede crear tan muchos entornos cuando deseas utilizar la orden virtualenv camino/
a/newenv. Esto creará un newenv directorio en la ubicación especificada, conteniendo un
Subdirectorio/ de cubo y un lib/pitón2.7 subdirectorio.

En cubo/ encontrarás varios scripts:

fActiva: El guión no es ejecutado, es sourced utilizando el construido-


enconchade fuente.Esto activará el entorno por ajustar la variable de entorno
del CAMINO para incluir el directorio/ de cubo del virtualenv. También
instala una función de concha llamó deactivate, el cual te puede correr para salir
el virtualenv, y cambia la concha incita para dejar sabes qué virtualenv es
actualmente activó
fpip: Esto es una versión especial delpiporden qué actos dentro
delvirtualenv sólo.
fPitón: Esto es un wrapper alrededor de vuestro intérprete de Pitón del sistema
qué usos lospaquetes instalados en el virtualenv.
5
Instalando el Odoo Entorno de Desarrollo

El construido-en concha de fuente es también disponible (como punto


solo, seguido por un espacio, y el camino al archivo a fuente). La forma
de atajo es perfectamente bien, pero nos aferraremos a fuente en
este libro para readability.

Hay dos maneras principales de utilizar un virtualenv. Lo puedes activar tan muestramos en
la receta
(Y llamada deactivate cuándo estás hecho) o puedes utilizar los guiones en el
directorio/ de cubo del entorno explícitamente por llamarles con su camino lleno, en qué
caso no necesitas para activar el virtualenv. Esto es principalmente un asunto de gusto,
así que tienes que experimento y descubrir which el estilo te convienes mejor para qué caso.
Puedes tener guiones de Pitón ejecutable con la primera línea que parece el siguiente:

#! /usr/Cubo/env pitón

Estos serán más fáciles de utilizar con un activados virtualenv. Esto es el caso con el
odoo.py guión, which te puede por tanto llamada en la manera siguiente:
$ ./odoo.py -d odoo-Prueba --addons-camino=addons --db-filtro=odoo-
probar$

PostgreSQL Configuración
En un GNU/sistema de Linux, Odoo trabaja muy bien con el default valores de
psycopg2 , el módulo de Pitón utilizó a access un PostgreSQL base de datos:
f Passwordless Autentificación si el usuario de base de datos tiene el mismo nombre
como el usuario actual en conexiones locales
f Usos de conexión local casquetes de ámbito
f del Unix El servidor de base de datos
escucha en portuario 5432

En aquel caso, there no tiene nada de particular para hacer: utilizamos el postgres
usuario administrativo para crear un usuario de base de datos qué participaciones
nuestro login nombre y darlo el correcto de crear bases de datos nuevas. Entonces
creamos una base de datos nueva con el mismo nombre como el usuario nuevo, el
cual será utilizado como default base de datos cuándo utilizando el psql orden.
Cuando en un servidor de desarrollo, es VALE para dar el PostgreSQL usuario más derechos
y para utilizar el --superuser orden-opción de línea más que justo --createdb. El efecto
neto es que este usuario puede entonces también create otros usuarios y globalmente
dirigir el caso de base de datos. Si sientes --superuser es demasiado, puedes todavía
quiere uso --createrole además de --createdb cuándo creando vuestro usuario de
base de datos. Evita hacer este encima servidores de producción cuando dé additional
apalancamiento a un atacante explotando una vulnerabilidad en alguna parte del código
desplegado (ve Capítulo 16, Despliegue de Servidor).
Si quieres utilizar un usuario de base de datos con un diferente login, necesitarás
proporcionar una contraseña para el usuario. Esto está hecho por pascantar el --
pwprompt bandera en la línea de orden cuándo creando el usuario, en qué caso la orden
incitará tú para la contraseña.

6
Capítulo 1

Si el usuario ya ha sido creado y quieres poner una contraseña (o modificar una


contraseña olvidada) you puede utilizar la orden siguiente:
$ psql -c "Altera función $(whoami) con contraseña 'newpassword'"

Si esta orden falla con un mensaje de error que dice que la base de datos
no existe, es porque no creaste una base de datos nombrada después de
vuestro login nombre en paso 3. Aquello es bien; justo añadir el --
dbname opción con una base de datos de existir nombre como --
dbname plantilla1.

Git Configuración
En algún punto en el libro, necesitarás utilizar git cometer. Esto fallará a no ser que algunos
la configuración básica está actuada; you necesidad de proporcionar Git con vuestro nombre
y dirección de correo electrónico. Git Te recordará para hacer este con un mensaje de error
bueno, pero puedes también él ahora.

Esto es también algo para mantener en importar si estás utilizando


un servicio como Travis para integración continua, y vuestra
necesidad de guiones de la prueba para actuar algunos git fusiona:
tienes que proporcionar un dummy nombre y email para el
fusionando para tener éxito.

Descargando el Odoo código de fuente


Descargando el Odoo base de código está hecha por actuar un git operación de clon.
Ser paciente cuandoth es tomará algún tiempo. Las opciones --rama 9.0 --solo-la
rama evita descargar otras ramas y salvar un poco tiempo. El --opción de profundidad
también puede soler evitar descargando la historia de repositorio entera, pero el downside de
aquella opción es que tú will no ser capaz de explorar aquella historia cuándo buscando
asuntos.
El Odoo los desarrolladores también proponen nightly complexiones, los cuales son
disponibles como tarballs y paquetes de distribución. La ventaja principal de utilizar un git el
clon es que serás capaz de actualizar vuestro repository cuándo el bicho nuevo fija está
cometido en el árbol de fuente. También serás capaz a fácilmente probar cualquier
propuesto fija y regresiones de pista, así que puedes hacer vuestro bicho informa más
preciso y útil para los desarrolladores.

Empezando el caso
Ahora viene elm oment has sido esperando a. Para empezar nuestro primer caso, primero
creamos una base de datos vacía nueva y entonces utilizar el odoo.py guión con la orden
siguiente-argumentos de línea:
f -d Nombre_de base de datos: Uso que base de datos por default.
7
Instalando elO doo Entorno de Desarrollo

f--db-Nombre=de base de datos_del filtro$: Sólo intentar conectar a las


bases de datos que emparejan la expresión regular suministrada. Uno Odoo la
instalación puede servir los casos múltiples que viven en las bases de datos
separadas y este argumento limita el disponibles databases. El final $ es
importante como la expresión regular está utilizada en modo de partido; esto evita
seleccionar los nombres que empiezan con la cuerda especificada.
f--addons-Directorio=de camino1,directorio2,...: Esto es una coma
lista separadade directorios en qué Odoo buscará addons. Esta lista está
escaneada en el tiempo de creación del caso para poblar la lista de disponible añadir-
en módulos en el caso.
Si estás utilizando un usuario de base de datos con una base de datos login diferente
de vuestro Linux login, necesitas pasar el following argumentos adicionales:

f--db_Anfitrión=localhost: uso un TCP conexión al servidor de


base de datosf--db_base de datos=de usuario_username: uso
la base de datos especificada login
f--db_Contraseña=de base de datos_de la contraseña: la
contraseña para utilizar para autenticarcontra el PostgreSQL server
Para conseguir una visión general de todas las opciones disponibles, uso el --argumento
de ayuda. Veremos mucho más sobre el odoo.py guión en este capítulo así como en
Capítulo 2, Dirigiendo Odoo Casos de Servidor.
Cuándo Odoo está empezado en una base de datos vacía, él abetost crear la estructura de
base de datos necesitó apoyar sus operaciones. También escanee el addons camino para
encontrar el disponible addon módulos, e insertar algunos los registros iniciales en la base
de datos. Esto incluye el admin usuario con el default contraseña admin which te utilizará
para autenticar con.
Odoo Incluye un servidor de HTTP. Por default, escucha encima todas interfaces de red
locales en TCP puerto 8069 así que señalando vuestro navegador de web a
http://localhost:8069/ te diriges a vuestro caso nuevamente creado.

hay más…
Yon la receta, descargamos la versión estable más tardía de Odoo utilizando la orden
siguiente:

$ git Clon -b 9.0 --solo-rama https://github.com/odoo/odoo.git

Esto utiliza la rama oficial mantenida por Odoo. Uno emite con esta rama es que el bicho fija
contribuido por la comunidad no es siempre fusionado en una moda oportuna. El Odoo
Asociación Comunitaria (OCA) mantiene una rama paralela en qué fija y las mejoras son peer-
revisados por el comunitarios y tender para ser fusionado más rápido que en el oficial branch.
No es un tenedor de Odoo, y la versión más tardía de Odoo está fusionado atrás a aquella
rama diariamente.
Puedes querer utilizar él para vuestros desarrollos y despliegues, en qué caso necesitas
clonar Odoo así:
$ git Clon -b 9.0 --https de rama sola://github.com/oca/ocb.git odoo

8
Capítulo 1

Gestor Odoo los entornos que utilizan


la orden de inicio
A menudo querremos utilizar módulos hechos de encargo o comunitarios con nuestro
Odoo caso. Manteniéndoles en un directorio separado lo hace más fácil de instalar
upgrades a Odoo o troubleshoot asuntos de nuestros módulos hechos de encargo. Justo
tenemos que añadir aquel directorio al addons el camino y ellos serán disponibles en
nuestro caso, justo como los módulos de núcleo son.
Es posible de pensar sobre este directorio de módulo como un Odoo environment. El Odoo orden
de inicio lo hace fácil de organizar Odoo casos como directorios, cada cual con sus módulos
propios.

Preparándose
Para esta receta necesitamos tener ya instalados Odoo. Suponemos que sea en
~/odoo-dev/odoo, y que el virtualenv está activado.

Esto significa que la orden siguiente exitosamente tendría que empezar un Odoo servidor:

$ ~/odoo-dev/odoo/odoo.py

Cómo para hacerlo...


Para crear un entorno de trabajo para vuestro caso, necesitas seguir estos pasos:

1. Cambio al directorio donde Odoo es: $


cd ~/odoo-dev

2. Escoger un nombre para el entorno y crear un directorio para él:


$ mkdir mi-odoo

3. Cambio a aquel directorio y empezar un Odoo caso de servidor para aquel


entorno: $ cd mi-odoo/
$ ../odoo/odoo.py Inicio

Cómo trabaja...
El Odoo orden de inicio es un atajo para empezar un caso de servidor que utiliza el
directorio actual. El nombre de directorio es automáticamente utilizado como el nombre de
base de datos (para el -d opción), y el directorio actual es automáticamente añadido al
addons camino (el --addons-camino option) mientras contiene un Odoo addon módulo.
En la receta de preceder no verás el directorio actual en el addons camino porque no
contiene cualesquier módulos todavía.
9
Instalando el Odoo Entorno de Desarrollo

Allí ha más
Pordef ault el directorio actual está utilizado, pero el --opción de camino te dejas
para poner un camino concreto para utilizar en cambio. Por ejemplo, esto trabajaría de
cualquier directorio:
$ ~/odoo-dev/odoo/odoo.py Inicio --camino=~/odoo-dev/mi-odoo

La base de datos al uso también puede ser overridden utilizando el habitual -d opción. De
hecho, todo el otro habitual odoo.py orden-argumentos de línea, exceptúa --addons-
camino, trabajará. Por ejemplo, para poner el servidor que escucha puerto, uso la orden
siguiente:
$ ../odoo/odoo.py Inicio --xmlrpc-portuario=8080

Cuando podemos see, el Odoo orden de inicio puede ser una manera conveniente a
quickstart Odoo casos con su directorio de módulo propio.

Gestor Odoo bases de datos de servidor


Cuándo trabajando con Odoo, todo el dato de vuestro caso está almacenado en un
PostgreSQL base de datos. Todo el estándar database herramientas de administración
sueles es disponible, pero Odoo también propone una interfaz de web para algunas
operaciones comunes.

Preparándose
Suponemos que vuestro entorno de trabajo está instalado y tienes un caso que corre. No
Lo empieza utilizando el odoo.py start manda mostrado en la receta anterior, cuando
configura el servidor con algunas opciones qué interferir con multi-administración de base
de datos.

Cómo para hacerlo...


El Odoo interfaz de administración de la base de datos proporciona herramientas para crear,
duplicado, saca, atrás arriba, y restore una base de datos. hay también una manera de
cambiar la contraseña maestra qué suele protege acceso a la interfaz de administración de
la base de datos.

Acceso la interfaz de Administración de la Base de datos


Para acceder la base de datos, la necesidad de pasos siguiente para ser actuado:

1. Va all ogin pantalla de vuestro caso (si estás autenticado, registro fuera).
2. Clic en el Dirigir enlace de Bases de datos. Esto navigate a http://
localhost:8069/base de datos/de web/director (también puedes
señalar vuestro navegador directamente a aquel URL.).
10
Capítulo 1

Set O cambiar la contraseña maestra


Si has instalado vuestro caso con default valores, y no todavía lo modificó tan explicado en
la sección siguiente, la pantalla de administración de la base de datos mostrará un aviso
que te dice que la contraseña maestra no es puesta, y undvising te para poner uno, con un
enlace directo:

1. Para poner la Contraseña Maestra, puedes clic en aquel enlace. Conseguirás


una caja de diálogo que te pregunta para proporcionar la contraseña nueva:

2. Tipo en un no-contraseña nueva trivial y clic en Co ntinue.


3. Cuándo la contraseña maestra es ya puesta, clic el Pone botón de Contraseña
Maestra en el fondo de la pantalla para cambiarlo
4. En la caja de diálogo mostrada, tipo la contraseña maestra anterior y el nuevo un, y
entonces el clic encima Continúa.

11
Installing El Odoo Entorno de Desarrollo

La contraseña maestra es en el archivo de configuración del servidor bajo el


admin_ llave de contraseña. Si el servidor estuvo empezado sin especificar
un archivo de configuración, un nuevo uno será generado en
~/.openerp_serverrc. Ver la receta próxima para más información sobre
el archivo de configuración.

Creando una base de datos nueva


Esta caja de diálogo puede soler crear un caso de base de datos nuevo cuál será
manejado por el actual Odoo servidor:
1. En la pantalla de administración de la base de datos, clic en el Create botón de
Base de datos en el fondo de la pantalla.

2. Llenar la forma en como sigue:


‰‰ Contraseña maestra: La contraseña maestra para este caso. Nombre
‰‰ de base de datos: Entrada el nombre de la base de datos deseas
‰‰ crear.
Language: Seleccionar la lengua deseas ser instalado por default en la
‰‰
base de datos nueva.
Contraseña de admin usuario: Tipo la contraseña quieres puesto para el
admin usuario del caso nuevo.
12
Capítulo 1

‰‰ Dato de manifestación de la carga: Control esta caja a have dato de


manifestación. Esto es útil de correr pruebas o instalar una manifestación
para un cliente, pero no tendría que ser comprobado para una base de
datos significó para contener dato de producción.
3. Clic en el Continuar botón, y esperar un poco hasta la base de datos nueva está
inicializada. You Entonces será redirigido al caso, conectado como el Administrador.

Troubleshooting
Si estás redirigido a un login pantalla, esto es probablemente porque la
opción --db-el filtro estuvo pasado a Odoo y el nombre de base
de datos nuevo no emparejó el nombre de basede dato nuevo. Nota
que el odoo.py orden de inicio esto silenciosamente, haciendo sólo
la base de datos actual disponible. Para trabajar alrededor de este,
sencillamente retomar Odoo sin la orden de inicio, cuando mostrado en
la primera receta de este capítulo. Si tienes una configuración file (ve el
Almacenando la configuración de caso en una receta de archivo más
tarde en este capítulo), entonces comprueba que el db_opción de
filtro es unset o puesto a un valor que empareja el nombre de base de
datos nuevo.

Duplicando una base de datos


Muy a menudo tendrás una base de datos de existir unnd quieres experimento con él para
probar un procedimiento o correr una prueba, pero sin modificar el dato de existir. La
respuesta es sencilla: duplicado la base de datos y correr las pruebas en la copia. Repite tan
muchas veces cuando requirió:

1. En la pantalla de administración de la base de datos, clamer en el enlace Duplicado


luego al nombre de la base de datos deseas clonar.
13
Instalando el Odoo Entorno de Desarrollo

2. Rellenar la forma:
‰‰ Contraseña maestra: la contraseña maestra del Odoo el
‰‰
servidor Nuevo Name: el nombre quieres dar a la copia
3. Clic en el Continuar botón.
4. Puedes entonces clic en el nombre de la base de datos nuevamente creada
en la pantalla de administración de la base de datos para acceder el login
pantalla para aquella base de datos.

Sacando una base de datos


Cuándo has finiderramado vuestras pruebas, querrás limpiar arriba del duplicó bases de
datos. Para hacer este, actuar los pasos siguientes:
1. En la pantalla de administración de la base de datos, clic en el Eliminar enlace luego
al nombre de la base de datos quieres sacar.

2. Rellenar la forma; introducir la Contraseña Maestra, el cual es la contraseña


maestra del Odoo servidor.
3. Clic el Eliminar botón.

Amonestación! Pérdida de dato potencial!


Si seleccionaste la base de datos incorrecta, y tener ninguna copia de
seguridad, hay ninguna manera de recuperar el dato perdido.

14
Capítulo 1

Respaldando arriba de una base de datos


Para crear una copia de seguridad, la necesidad de pasos siguiente para ser actuado:

1. En la pantalla de administración de la base de datos, clic el enlace de Copia de


seguridad luego a la base de datos quieres atrás arriba.

2. Rellenar la forma:
‰‰ Contraseña maestra: la contraseña maestra del Odoo servidor.
‰‰ Formato de copia de seguridad: siempre cremallera de uso para una base de
datos de producción, cuando es el formato de copia de seguridad lleno real
único. Sólo utilizar el pg_formato de vertedero para una base de datos de
desarrollo donde tú no realmente cuidado sobre elf ile tienda (admin por
default).

3. Clic el botón de Copia de seguridad. El archivo de copia de seguridad será


descargado a vuestro navegador.
15
Instalando el Odoo Entorno de Desarrollo

Restaurando una copia de seguridad de base de datos


Si necesitas restaurar una copia de seguridad, este is qué necesitas hacer:

1. En la pantalla de administración de la base de datos, clic el Restaurar botón de


Base de datos en el fondo de la pantalla.

2. Rellenar la forma:
‰‰ Contraseña maestra: la contraseña maestra del Odoo servidor.
‰‰ Archivo: un anteriorly descargó Odoo copia de seguridad.
‰‰ Nombre de base de datos: proporcionar el nombre de la base de datos en
qué la copia de seguridad será restaurada. La base de datos no tiene que
existir en el servidor.
‰‰ Generar una base de datos nueva uuid: deja unchecked si estás instalando
una base de datos cuál ha sido eliminado del servidor; otherwise
comprueba la caja. Hay poca diferencia entre ellos, y si en duda, dejándolo
unchecked es una elección segura.
3. Clic el Continuar botón.

Nota: no es posible de restaurar una base de datos arriba de él. Si


intentas hacer este, conseguirás un mensaje de error (la base de datos
restaura error: la base de datos ya existe). Necesitas sacar la base de
datos primero.
16
Capítulo 1

Cómo trabaja...
Estas características, aparte del Cambio pantalla de contraseña maestra, corrido
postgresql órdenes de administración en el servidor e informe atrás a través de la
interfaz de web.
La contraseña maestra es una pieza muy importante de información qué vidas únicas en el
Odoo archivo de configuración del servidor y nunca es almacenado en la base de datos. Allí
utilizado para serun d efault valor de admin , pero utilizando este valor es una
responsabilidad de seguridad cuando es bien sabido. En Odoo v9, esto está identificado
como un "unset" la contraseña maestra y tú consiguen instados para cambiarlo cuándo
accediendo la interfaz de administración de la base de datos. Incluso si está almacenado
en el archivo de configuración bajo el admin_passwd entrada, esto no es igual como la
contraseña del admin usuario; estos son dos contraseñas independientes : la contraseña
maestra está puesta para un Odoo proceso de servidor, el cual él puede manejar casos de
base de datos múltiple, cada cual del cual tiene un independiente admin usuario con su
contraseña propia.

Consideraciones de seguridad: Recuerda que estamos considerando un


entorno de desarrollo en este capítulo. El Odoo interfaz de administración de
la base de datos es algo cuál necesita ser asegurado cuándo you está
trabajando en un servidor de producción cuando da acceso a mucha
información sensible, especialmente si los anfitriones de servidor Odoo
casos para varios clientes diferentes. Esto será cubierto en Capítulo 16,
Despliegue de Servidor.

Para crear una base de datos nueva, Odoo utiliza el PostgreSQL createdb utilidad y llama
el interno Odoo función para inicializar la base de datos nueva en la misma manera cuando
cuando empiezas Odoo en una base de datos vacía.
Para duplicar una base de datos, Odoo utiliza el --opción de plantilla de createdb
pasando la base de datos original como un argumento. Esto esencialmente duplica la
estructura de la base de datos de plantilla en la base de datos nueva que utiliza interno y
optimizado PostgreSQL rutinas, el cual es mucho más rápido que creando una copia de
seguridad y restaurándolo (especialmente cuándo utilizando la webi nterface cuál requiere
descargar el archivo de copia de seguridad y cargándolo otra vez).
Copia de seguridad y restaurar las operaciones utilizan el pg_vertedero y pg_restaurar
utilidades respectivamente. Cuándo utilizando el .Formato de cremallera, la copia de
seguridad también incluirá una copia del archivo almacena qué contains una copia de los
documentos cuándo configuras Odoo a no mantener estos en la base de datos, el cual es el
default en 9.0. A no ser que lo configuras otherwise, estos archiva vivos en
~/.Participación/local/Odoo/filestore.
17
Instalando el Odoo Development Entorno

Si la copia de seguridad consigue grande, descargándolo puede fallar, tampoco


porque el
Odoo Servidor él no es capaz de manejar el archivo grande en memoria o si
las carreras de servidor detrás de un inversos proxy (ve Capítulo 16,
Despliegue de Servidor) porque hay unl imit a la medida de respuestas de
HTTP puestas en el proxy.
En cambio, para las mismas razones, tú probablemente asuntos de
experiencia con la base de datos restauran operación. Cuándo empiezas
correr a estos asuntos, es hora de invertir en una copia de seguridad
externa más robusta tanlution.

hay más...
Experimentado Odoo los desarrolladores generalmente no utilizan la interfaz de
administración de la base de datos, y actuar las operaciones de la línea de orden. Para
inicializar una base de datos nueva con demo dato para caso, el siguiente un-liner puede ser
utilizado:
$ createdb testdb && odoo.py -d testdb

La bonificación adicional de esta línea de orden es que puedes pedir instalación de addons
mientras eres en él utilizando para caso -i venta,compra,stock (más encima esto en
Capítulo 2,
Gestor Odoo Casos de Servidor).

Para duplicar una base de datos, parón el servidor, y correr la orden siguiente:

$ createdb -T dbname newdbname


$ cd ~/.Participación/local/Odoo/filestore # adapta si has cambiado el
dato_ dir
$ cp -r dbname newdbname
$ cd -

Nota que en el contexto de desarrollo, tarchive la tienda es a menudo omitió.

El uso de createdb -T trabajos únicos si hay no sesiones activas en la


base de datos, el cual significa tienes que cerrar vuestro Odoo servidor
antes de duplicar la base de datos de la línea de orden.

Para sacar un caso, corrido la orden siguiente:

$ dropdb dbname
$ rm -rf ~/.Participación/local/Odoo/filestore/dbname

Para crear una copia de seguridad (suponiendo el PostgreSQL el servidor está corriendo
localmente), uso la orden siguiente:
$ pg_Vertedero -Fc -f dbname.Vertedero dbname
$ Alquitrán cjf dbname.tgz dbname.Vertedero
~/.Participación/local/Odoo/filestore/dbname

18
Capítulo 1

Para restaurar la copia de seguridad, corrido la orden siguiente:

$ Alquitrán xf dbname.tgz
$ pg_Restaurar -C -d dbname dbname.Vertedero

Amonestación!
Si vuestro Odoo el caso utiliza un usuario diferente para conectar a la
base de datos you necesidad de pasar -U username de modo que
el usuario correcto es el dueño de la base de datos restaurada.

Almacenando la configuración de caso en


un archivo
El odoo.py el guión tiene docenas de opciones, y es tedioso de recordarles todo y para
recordar para ponerles correctamente cuándo empezando el servidor. Afortunadamente,
es posible de almacenarles todo en un archivo de configuración y a sólo especificar a
mano los quieres alterar, por ejemplo, para desarrollo.

Cómo para hacerlo...


Para generar un archivo de configuración para vuestro Odoo instance, corrido la orden
siguiente:

$ odoo.py --Salvar --config myodoo.cfg --Parón-después de que-init

Puedes añadir opciones adicionales, y sus valores serán salvados en el archivo generado. Todo
el unset las opciones serán salvadas con su default conjunto de valor. Para conseguir una lista
de opciones posibles, uso:
$ odoo.py --Ayudar | menos

Esto proporcionará tú con alguna ayuda aproximadamente lo que las varias opciones
actúan. Para convertir de la forma de línea de la orden a la forma de configuración, uso el
nombre de opción largo, sacar el principal dashes, y convertir el dashes en el medio a
underscores: --sin-demo deviene sin_demo. Estos trabajos para más opciones, pero
hay unas cuantas excepciones listó en la sección próxima.
Editar el archivo myodoo.cfg (Uso la mesa en la sección siguiente para algunos parámetros
puedes querer cambio). Entonces para empezar el servidor con el salvó opciones, corridos la
orden siguiente:
$ odoo.py -c myodoo.cfg

El --config la opción es generalmente abreviada tan -c


19
Instalando el Odoo Entorno de Desarrollo

Cómo trabaja...
En empezar arriba, Odoo carga su configuración en tres pases. Primero un conjunto de
default los valores para todas las opciones está inicializado del código de fuente. Entonces
la configuración es parsed, y cualquier valor definido en el archivo overrides el defaults.
Finalmente, la orden-opciones de línea están analizadas y sus valores override la
configuración obtenida del pase anterior.
Cuando mencionado más temprano, los nombres de las variables de configuración pueden
ser encontrados de los nombres de la orden-opciones de línea por sacar el principal dashes
unnd convirtiendo el medio dashes a underscores. Hay unas cuantas excepciones,
notablemente:

Línea de orden Archivo de configuración


--db-Filtro dbfilter
--No-xmlrpc xmlrpc = Cierto / Falso
--Base de datos db_Nombre
Depura_el modo = Cierto /
--Depurar Falso
--i18n-importación / --i18n-
exportación Inutilizable

Aquí es una lista de las opciones generalmente puestas a través del archivo de configuración:

Opción Formato Uso


Sin_demo Impide módulo demo dato de ser cargado.
Una lista de nombres de directorio en qué el
addons_Camino Coma servidor
Lista separada
de Busca addons (ve Capítulo 2, Dirigiendo Odoo
Caminos Casos de servidor).
admin_passwd Texto La contraseña maestra (ve receta anterior).
Dato_dir Camino a un Un directorio en qué el servidor almacenará sesión
Directorio Información, addons descargó del
Internet, y documentos si habilitas el archivo
Tienda.
db_Anfitrión Nombre anfitrión El nombre del servidor que corre el PostgreSQL
Servidor. Uso Falso de utilizar Ámbito de Unix local
Casquetes, y localhost para utilizar TCP casquetes
Localmente.
Usuario de base
db_noser de datos
login
Usuario de base Esto es generalmente vacío si db_el anfitrión
db_Contraseña de datos es Falso y
db_El usuario tiene el mismo nombre como el
Contraseña usuario que corre
El servidor. Leído la página de hombre de
pg_hba.conf.
Para más información en este.

20
Capítulo 1

Opción Formato Uso


Nombre de base Utilizado para poner el nombre de base de datos en
Base de datos de datos qué algunos
Las órdenes operan por default). Esto no limita
Las bases de datos en qué el servidor actuarán. Ver
el
Siguiente dbfilter opción parathi s.
dbfilter Un regular La expresión tendría que emparejar el nombre del
Las bases de datos consideraron por el servidor. Si
Expresión te corrido
El sitio web, tenga que emparejar una base de
datos sola,
Así que parezca ^databasename$. Más
Información en este es en Chapter 16, Servidor
Despliegue.
xmlrpc_Interfaz Dirección de IP Defaults A 0.0.0.0 , significando el servidor escucha
De una red Encima todas las interfaces
Interfaz
Número
xmlrpc_Puerto portuario Los puertos en qué el Odoo el servidor escuchará.
longpolling_Puert Tú need para especificar ambos para correr
o múltiple Odoo
Servidores en el mismo anfitrión.
longpolling_Puerto
Es sólo utilizado si los trabajadores no es 0.
Camino a un
logfile archivo El archivo en qué Odoo escribirá sus registros.
Verbosidad de
Nivel_de registro registro Especificar el nivel de logging. Aceptó valores (en
Nivel Orden de verbosidad creciente): crítico, error,
Advierte, info, depura, depura_rpc,
depura_rpc_
Respuesta, depura_sql.
El número de procesos de trabajador. Ve Capítulo
Trabajadores Entero 16,
Despliegue de servidor, para más información.
Ninguna_base de Puesto a Cierto de inutilizar listando de bases de
datos_list Cierto / Falso datos.
Ve Capítulo 16, Despliegue de Servidor, para más
Información.

hay más...
El parsing del archivo de configuración por Odoo está hecho utilizando la Pitón
ConfigParser módulo. Este módulo apoya definir valores para variables de los valores de
otras variables que utilizan el %(sección.Variable)s notación. Puedes omitir sección
si el valor proviene la misma sección o si está definido en el especial [DEFAULT] sección.
Para caso, si quieres define la base de datos login para ser igual como el nombre de base
de datos, puedes escribir el siguiendo en vuestro Odoo archivo de configuración:
[Opciones]
db_Nombre = projectname
db_Usuario = %(options.db_nombre)s

21
Instalando el Odoo Entorno de Desarrollo

Un muy common el uso es para definir un prefijo común para los caminos del addons:

[DEFAULT]
Casa = /de
proyecto/odoo/proyecta/proyecto1 env =
dev
Prefijo = %(proyecto)s/%(env)s

[Opciones]
addons-Camino =
%(prefijo)s/odoo/addons,%(prefijo)s/OCA/servidor-dato de
herramientas_dir = %(prefijo)s/dato_dir

Activando el Odoo herramientas de


desarrollador
Cuándo utilizando Odoo como desarrollador, necesitas saber cómo para activar Modo de
Desarrollador en la interfaz de web para acceder el adelantó carta de encuadres e
información de desarrollador.

Cómo para hacerlo...


Para activar Desarrollador Moda en la interfaz de web:

1. Conecta a vuestro caso y autenticar (no necesariamente tan admin; esta función es
disponible a todos los usuarios, pero el Administrador tiene más las herramientas
disponibles).
2. Clic en el abajo flecha luego a vuestro nombre de usuario en el superior correcto
corner de la página .
3. En la gota-abajo carta, clic encima Aproximadamente.

22
Capítulo 1

4. En el diálogo boxea cuál está mostrado, el clic encima Activa el modo de


desarrollador en la esquina correcta superior.

Es también possible para activar el modo de desarrollador por editar el


URL: antes de la # señal, inserta ?Depura=. Para caso, si estás
empezando de: http://localhost:8069/carta#de
web_id=102&acción=94, entonces necesitas cambiar esto a:
http://localhost:8069/web?Depura=#carta_ id=102&acción=94.

23
Instalando el Odoo Entorno de Desarrollo

5. Para salir modo de desarrollador, puedes editar el URL y sacar aquella cuerda, cierra
vuestro tabulador de navegador y abrir un nuevo un, o utilizar el Dejar Depurar opción de
Modo en el fondo del depurar gota-abajo carta luego a la carta de usuario en el derecho
superior de la pantalla.

Cómo trabaja...
Cuando en modo de desarrollador, tres cosas pasan:

fEl Javascript y CSS el códigoenvió al navegador no es minified, el cual


significaque las herramientas de desarrollo de la web de vuestro navegador
son fáciles de utilizar para depurar el código de Javascript (más encima esto en
Capítulo 15, Desarrollo de Cliente de la Web).
fConsigues tooltips cuándo cercando sobre un campo en una vista de forma o sobre una

columna en vista de lista queproporciona técnico information sobre el campo (nombre


interno, tipo, y tan encima).
fUna gota-abajo la carta con un icono de Bicho está mostrada luego a la carta del
usuario en la esquinacorrecta superior que da acceso a la información técnica
sobre el ser de modelo mostró, la varias vista relacionada definitions, el workflow,
administración de filtro hecho de encargo, y tan encima.

Amonestación!
Prueba vuestro addons ambos con y sin modo de desarrollador,
cuando el unminified las versiones de las bibliotecas de
Javascript pueden esconder bichos qué mordisco único tú en el
minified versión.
24
Capítulo 1

Actualizando Odoo de fuente


Vimos en la primera receta cómo para instalar Odoo de fuente por utilizar el git repositorio.
El beneficio principal de este encuadre está siendo capaz de actualizar el código de fuente
de Odoo utilizando git para conseguir el bicho más tardío fija.

Getting A punto
Parón cualquier caso actualmente corriendo con el Odoo fuente estás a punto de
actualización.

Marca una copia de seguridad de todas las bases de datos te preocupas aproximadamente
en caso algo va malo. Esto es evidentemente algo necesitas hacer para bases de datos de
producción. Ver el Managing Odoo receta de bases de datos del servidor para instrucciones.
Entonces hacer una nota de la versión actual de la fuente estás corriendo. La manera
mejor es para crear una etiqueta ligera que utiliza la orden siguiente:
$ cd ~/odoo-dev/odoo
$ git checkout 9.0
$ git Etiqueta 9.0-antes de que-actualización-$(fecha --iso)

Cómo para hacerlo...


Para actualizar el código de fuente de Odoo, uso la orden siguiente:

$ git Atracción –-ff-único

Esto fetch la versión más tardía del código de fuente cometido a la rama actual.

Para actualizar un caso que corre en este código, corrido la orden siguiente:

$ odoo.py -c myodoo.cfg --Parón-después de que-init -u base

-u Es la notación de atajo para el --opción de actualización de odoo.py


.

Si no tienes una base de datos puesta en el archivo de configuración, tendrás que


añadir el -d nombre_de base de datos option. Aquella orden es para ser
repetido para todos los casos que corren con esta versión del código de fuente.
25
Instalando el Odoo Entorno de Desarrollo

Si la actualización falla, no pánico, tienes copias de seguridad.

1. Leído el mensaje de error cuidadosamente. Save lo A un archivo, cuando sea útil


de hacer un informe de bicho más tarde.
2. Si no puedes representar fuera lo que el problema es, restaurar el servicio;
restaurar el Odoo código de fuente a la versión anterior, el cual es sabido de
trabajar utilizando la etiqueta pusiste antes de actualizar el source versión:
$ git Reinicialización --duro 9.0-antes de que-actualización-
$(fecha --iso)

3. Gota las bases de datos rotas y restaurarles de las copias de seguridad hiciste (ve el
Gestor Odoo receta de bases de datos del servidor para instrucciones).
4. Retomar vuestros casos y decir vuestros usuarios que elu pgrade ha sido aplazado.

Nota que en vida real, esto nunca tendría que pasar en una base de datos
de producción, porque habrías probado el upgrade por adelantado en una
copia de la base de datos, fijado los asuntos, y sólo hechos el upgrade en
el servidor de producción after haciendo seguro que corre perfectamente.
Pero a veces, todavía consigues sorpresas, tan incluso si eres realmente
seguro, marca una copia de seguridad.

Cómo trabaja...
Actualizando el código de fuente está hecho por hacer seguro somos en la rama correcta
que utiliza git checkout, y entonces fetching las revisiones nuevas que utilizan git
atracción. El --ff-la opción única causará un fracaso si tienes local comete no
presentar en el repositorio remoto. Si esto pasa y quieres mantener vuestros cambios,
puedes utilizar git atracción (sin --ff-único) para fusionar los cambios remotos con
el vuestro; otherwise, uso git reinicialización --origen duro/9.0 para forzar la
actualización, discarding vuestras modificaciones locales.
La orden de actualización utiliza las opciones siguientes:

f -c: Especificar el archivo de configuración


f --Parón-después de que-init: parón el caso cuándot actualice es encima
f -u Base o --base de actualización: peticiones la actualización del módulo de
base
26
Capítulo 1

Cuándo actualizando un módulo, Odoo hace el siguiente:

f Actualiza la estructura de base de datos para los modelos definió en el module para
qué los cambios de estructura. Para actualizaciones en la rama estable de Odoo,
tendría que haber no tales cambios, pero esto puede pasar para vuestro propio
f addons o tercer partido addons.
Actualiza los registros de base de datos almacenaron en archivos de datos del
módulo, más notablemente tve. Él entonces recursively actualiza los módulos
instalados qué tiene declarado una dependencia en el módulo.
Desde el módulo de base es una dependencia implícita de todo Odoo módulos,
actualizándolo provocará una actualización de todos los módulos instalados en vuestro
instance. Para actualizar todos los módulos instalados, el alias todos pueden ser
utilizados en vez de base .
27
2
Gestor Odoo Servidor
Casos
En este capítulo, aprenderemos aproximadamente:

f Configurando el addons camino


f Actualizando el addon los módulos listan
f Estandarizar vuestro diseño de directorio del
f caso que Instala y upgrading local addon los
f módulos que Instalan addon módulos de
f GitHub Aplicando cambios a addons
f Aplicando y probando peticiones de atracción
propuesta

IntroductIón
En Capítulo 1, Instalando el Odoo Entorno de Desarrollo, hemos visto cómo para instalar un
Odoo el caso que utiliza sólo el núcleo "estándar" addons, los cuales están embarcados por el
editor. Este foco de capítulo encima añadiendo noncore addons a un Odoo caso, serlo túr propio
addons, o tercer-partido addons como los mantenidos por el Odoo Asociación Comunitaria
(OCA).

Sobre la terminología – addon versus módulo


En este libro, utilizaremos el plazo addon o addon módulo para referir a un
paquete de Pitón que respetos el formato esperado para ser instalado en Odoo.
La interfaz de usuario a menudo utiliza el módulo de palabra para este, pero
preferimos mantener este plazo para módulos de Pitón o paquetes que no es
necesariamente Odoo addons.
29
Dirige Odoo Casos de Servidor

Configurando el unddons camino


El addons el camino es un parámetro de configuración que listas los directorios, el cual será
buscado addon módulos por Odoo cuándo inicializa una base de datos nueva.
Los directorios listaron en el addons el camino está esperado para contener subdirectorios,
cada cual del cual es un addon módulo.

Preparándose
Esta receta supone tienes un caso a punto, con un archivo de configuración generó tan
descrito en Capítulo 1, Instalando el Odoo Entorno de Desarrollo. El código de fuente de
Odoo es disponible en ~/odoo-dev/odoo, y el archivo de configuración es en
~/odoo-dev/Mi-caso.cfg.

Cómo para hacerlo…


Para añadir el directorio ~/odoo-dev/local-addons al addons camino del caso, seguir
estos pasos:
1. Editar el archivo de configuración para vuestro caso ~/odoo-dev/mi-caso.cfg
2. Localizar la línea que empieza con addons_camino =. Por default, tenga que
parecer el siguiente:
addons_Camino = ~/odoo-dev/odoo/openerp/addons,~/odoo-
dev/odoo/ addons

3. Modificar la línea por anexar una coma seguida por el nombre del directorio
quieres añadir al addons camino:
addons_Camino = ~/odoo-dev/odoo/openerp/addons,~/odoo-
dev/odoo/ addons,~/odoo-dev/local-addons

Puedes ordenado que línea un poco por añadir una variable de raíz y utilizándolo
para acortar la definición de camino (ve Capítulo 1, Instalando el Odoo
Development Entorno, para más en este):
Raíz = ~/odoo-dev
addons_Camino =
%(raíz)s/odoo/openerp/addons,%(raíz)s/odoo/
addons,%(raíz)s/local-addons

4. Retomar vuestro caso:


$ ~/odoo-dev/odoo/odoo.py -c Mi-caso.cfg

30
Capítulo 2

Cómo él works…
Cuándo Odoo está retomado, el archivo de configuración está leído. El valor del
addons_variable de camino está esperada para ser una coma-lista separada de directorios.
Los caminos relativos están aceptados, pero
Son relativos al directorio laborable actual, y por tanto tendría que ser evitado en el
archivo de configuración.
Al llegar a este punto, el nuevo addons presente en ~/odoo-dev/local-addons no es
disponible en la lista de disponible addon módulos del caso. Para este, necesitas actuar
una operación extra explicada en la receta próxima, Actualizando el addon lista de
módulos.

Allí ha más…
Cuándo llamas el odoo.py guión por primera vez para inicializar una base de datos nueva,
puedes pasar el --addons-argumento de línea de orden de camino con una coma-lista
separada de directorios. Esto initialize la lista de disponible addon módulos con todo el addons
encontrados en el suministrados addons camino. Cuándo tú esto, tienes que explícitamente
incluir la base addons directorio (odoo/openerp/addons) así como el núcleo addons directorio
(odoo/addons). Ser prudente—si pusiste un espacio después de las comas— necesitarás citar la
lista de directorios.
Puedes utilizar el --salvar opción a también salvar el camino al archivo de configuración:
$ odoo/odoo.py -d mydatabase \ --addons-
Camino="odoo/openerp/addons,odoo/addons,local-addons" \ --
salvar -c odoo-proyecto.cfg –Parón-después de que-init

En este caso, utilizando los caminos relativos es VALE, desde entonces serán convertidos
a caminos absolutos en el archivo de configuración.

Actualizando el addon lista de módulos


Cuando dijimos en la receta anterior, cuándo añades un directorio al addons camino, justo
retomando el Odoo el servidor no es bastante para ser capaz de instalar uno del nuevo addon
módulos.
Una acción concreta está requerida para Odoo para escanear el addons camino y actualizar
la lista de disponible addon módulos.

Preparándose
Inicio túr caso, y conectar al caso que utiliza la cuenta de Administrador y activar el modo de
desarrollador (ve Capítulo 1, Instalando el Odoo Entorno de Desarrollo).
31
Dirige Odoo Casos de Servidor

Cómo para hacerlo…


Para actualizar la lista de available addon módulos en vuestro caso, necesitas actuar
los pasos siguientes:
1. Abierto la carta de Aplicaciones:

2. Clic encima Lista de Aplicaciones de la Actualización:

3. En el diálogo, clic en el botón de Actualización.


4. Al final de la actualización, puedes clic enth e primera entrada de Aplicaciones para
ver la lista actualizada de disponible addon módulos. Necesitarás sacar el default
filtro en Aplicaciones en la caja de búsqueda para ver todo de ellos.

32
Capítulo 2

Cómo trabaja…
Cuándo el botón de Actualización es clicked encima, Odoo leerá el addons variable de
configuración del camino, y para cada directorio en la lista, busque los subdirectorios inmediatos
que contienen un addon manifiesta archivo, el cual es un archivo nombró __openerp__.py,
almacenado en el addon directorio de módulo.
Odoo Lee el manifest esperando encontrar un diccionario de Pitón. A no ser que el
manifestar contiene un clave installable puesto a Falso , el addon módulo metadata
consta en la base de datos. Si el módulo era ya presente, la información está actualizada;
otherwise, un registro nuevo está creado. Si un anteriormente disponible addon el módulo
no es encontrado, el registro no es eliminado de la lista.

Estandarizando vuestro diseño de directorio


del caso
Recomendamos que vuestro desarrollo y entornos de producción todo uso un diseño
de directorio similar. Este estándarization probará útil cuándo tienes que actuar
operaciones de mantenimiento, y también alivie vuestro día a trabajo de día.
Esta receta crea una estructura de directorio que los grupos archiva habiendo ciclos de vida
similar o el propósito similar junto en estandarizado subdirectories. Siente libre de alterar
esta estructura para convenir vuestras necesidades, pero ser seguro para tener esto
documentó en algún lugar.

Cómo para hacerlo…


Para crear el diseño de caso propuesto, necesitas actuar los pasos siguientes:

1. Crea un directorio por caso:


$ mkdir ~/odoo-dev/projectname $
cd ~/odoo-dev/projectname

2. Crear una Pitón virtualenv en un subdirectorio llamó


env/: $ virtualenv env

3. Crea algunos subdirectorios, como sigue:


$ mkdir src Cubo local filestore registros

Las funciones de los subdirectorios son cuandosigue s:


‰‰ src/: Esto contiene el clon de Odoo él y del varios tercer-partido addons
proyectos (ve paso 4 en esta receta)
‰‰
‰‰

‰‰

‰‰
L /: Esto suele salvar vuestro caso-concreto addons cubo/:
o Esto incluye varios helper guiones de concha ejecutable
c filestore/: Esto está utilizado como tienda de archivo
a Registros/ (opcionales): Esto suele tienda los archivos
l de registro del servidor

33
Dirige Odoo Casos de Servidor

4. Clon Odoo e instalar los requisitos (ve Capítulo 1, Instalando el Odoo


Desarrollo Environment, para detalles):
$ git Clon https://github.com/odoo/odoo.git src/odoo
$ env/cubo/pip -r src/odoo/requisitos.txt

5. Salvar el guión de concha siguiente cuando cubo/odoo:


#!/Cubo/sh
RAÍZ=$(dirname $0)/..
PITÓN=$ARRAIGAR/env/pitón/de
cubo ODOO =
$RAÍZ/src/odoo/odoo.py
PYTHON ODOO -c $RAÍZ/projectname.cfg "$*"
Salir $?

6. Marca el guión ejecutable: $


chmod +x cubo/odoo

7. Generar un archivo de configuración para vuestro caso:


Cubo/odoo --parón-después de que-init –-salvar \
–-addons-Camino src/odoo/openerp/addons,src/odoo/addons,local
\ --datos-dir filestore

8. Añadir un .gitignore Archivo, preguntando para excluir dato/, env/, y src/


:
# dotfiles, con excepciones:
.*
.gitignore
# La pitón compiló
archivos *.py[co]
# emacs Archivos de copia de seguridad
*~
# No siguió subdirectorios
/env/
/src/
/filestore/
/Registros/

9. Crear un Git repositorio para este caso y añadir los archivos has añadido a
Git: $ git init
$ git Añade .
$ git Cometer -m "versión inicial de projectname"
34
Capítulo 2

Cómo trabaja…
Generamos una estructura de directorio limpia con claramente labeled directorios y dedicó
funciones. Especialmente, separamos el siguientes:
f El código mantenido por otras personas (en src/)
f El código concreto local
f El dato del caso

Por habiendo un virtualenv por proyecto, somos seguro que los proyectos' las
dependencias sonn ot yendo para interferir con las dependencias de otros proyectos que
puede ser correr una versión diferente de Odoo o utilizar tercio diferente-partido addon
módulos, los cuales necesitan versiones diferentes de dependencias de Pitón. Esto viene
en el coste de un poco espacio de disco.
En una manera similar, utilizando clones separados de Odoo y tercer-partido addon módulos para
nuestros proyectos diferentes, somos capaces de dejar cada cual de estos evolucionar
independientemente y sólo instalar actualizaciones en los casos que les necesita; de ahí,
reduciendo el riesgo de introducinregresiones de g.

El cubo/odoo el guión deja para correr el servidor sin teniendo que recordar los varios
caminos o activar el virtualenv. También pone el archivo de configuración para nosotros.
Puedes añadir guiones adicionales en allí para ayudar tú en vuestro día-a-trabajo de día, fo
caso, un guión para comprobar el tercio diferente-proyectos de partido que te necesidad de
correr vuestro caso.
Con respecto al archivo de configuración, sólo muestramos el bare opciones mínimas para
instalar aquí, pero evidentemente puedes poner más, como el nombre de base de datos,
the filtro de base de datos, o el puerto en qué el proyecto escucha. Complacer referir a
Capítulo 1, Instalando el Odoo Entorno de Desarrollo, para más información en este tema.
Finalmente, por gestor todo esto en un Git repositorio, deviene bastante fácil a replicate el
setup en un ordenador diferente y compartir el desarrollo entre un equipo.

Speedup Consejo
Para aliviar creación de proyecto, puedes crear un repositorio de
plantilla que contiene la estructura vacía, y tenedor que repositorio para
cada proyecto nuevo; esto salvará tú de retyping el cubo/odoo guión y
el .gitignore Archivo, y cualquiera otro archivo de plantilla
necesitas (configuración de integración continua, Readme.md,
ChangeLog, y tan encima).

Ve también
Si tú así aproximación, sugerimos probar fuera del buildout receta en Capítulo 16,
Despliegue de Servidor, el cual va uno da un paso más allá de este modo por utilizar
buildout para crear el entorno de caso.

35
Dirige Odoo Casos de Servidor

Instalando y upgrading local addon


módulos
El núcleo de la funcionalidad de Odoo vienefro m el addon módulos. Tienes una riqueza de
addons disponible cuando parte de Odoo él así como addon módulos que te puede
descargar del Internet o te escribir.
En esta receta, mostraremos cómo para instalar y upgrade addon módulos a través
de la web interface y de la línea de orden.
Los beneficios principales de utilizar la línea de orden para estas operaciones está siendo
capaz de actuar encima más de uno addon a la vez y teniendo una vista clara de los registros
de servidor como la instalación o progresos de actualización, el cual es muy noseful cuando
en el modo de desarrollo o cuándo scripting la instalación de un caso.

Preparándose
Tienes un Odoo el caso con su base de datos inicializó, el addons el camino es
correctamente puesto, y el addons la lista es actualizada.

Cómo para hacerlo…


hay two métodos posibles para instalar o actualización addons— puedes utilizar la interfaz de
web o la línea de orden.

De la interfaz de web
Para instalar un nuevo addon módulo en vuestra base de datos que utiliza la interfaz de web, uso
los pasos siguientes:

1. Conecta al caso que utiliza the cuenta de Administrador. Abierto la carta de Aplicaciones:
36
Capítulo 2

2. Clic en Aplicaciones.
3. Uso la caja de búsqueda para localizar el addon quieres instalar. Aquí es pocos
vierte para ayudar tú en esta tarea:
‰‰ Activar el filtro No Instalado
‰‰ Si buscando una funcionalidad concreta addon más que una
funcionalidad ancha addon, sacar el filtro de Aplicaciones
‰‰ Tipo una parte del nombre de módulo en la caja de búsqueda, y utilizar
esto como
‰‰
Filtro de módulo
Puedes encontrar que utilizando la vista de lista da algo más legible

4. Clic en el Instalar botón bajo el nombre de módulo (en la vista de iconos o en


la vista de forma).
Para actualizar un módulo ya instalado en vuestra base de datos, uso los pasos siguientes:

1. Conecta al caso que utiliza la cuenta de Administrador.


2. Abierto the carta de Aplicaciones.
3. Clic en Aplicaciones:

4. Uso la caja de búsqueda para localizar el addon quieres instalar.


Unos cuantos consejos: ‰‰ Activar el filtro Instalado
‰‰ Si buscando una funcionalidad concreta addon más que una funcionalidad
ancha addon, sacar el filtro de Aplicaciones
‰‰ Tipo una parte del addon nombre de módulo en la caja de búsqueda, y utilizar

esto un
Filtro de módulo
‰‰ Puedes encontrar que utilizando la vista de lista da algo más legible

5. Exhibición el módulo en la vista de forma, y clic en el Upgrade botón bajo el


module nombre.
37
Dirige Odoo Casos de Servidor

De la línea de orden
Para instalar algunos nuevos addons en vuestra base de datos, seguir los pasos siguientes:

1. Encontrar los nombres del addons. Esto es el nombre del directorio que contiene el
archivo
__openerp__.py Con fueradel camino principal.
2. Parón el caso. Si estás trabajando en una base de datos de producción, marca una
copia de seguridad.
3. Corrido la orden siguiente:
$ odoo/odoo.py -c Caso.cfg -d dbname -i addon1,addon2 --parón-
después de que-init

Puedes omitir -d dbname si esto está puesto en vuestro archivo de


configuración.

4. Retomar el caso.

Para actualizar un ya instalado addon módulo en vuestra base de datos, seguir los pasos
dados aquí:

1. Encontrar el nombre del addon módulo para actualizar; esto es el nombre del
directorio que contiene el __openerp__.py Archivo without el camino
principal.
2. Parón el caso. Si estás trabajando en una base de datos de producción, marca una
copia de seguridad.
3. Corrido la orden siguiente:
$ odoo/odoo.py -c Caso.cfg -d dbname -u addon1 \ --
parón-después de que-init

Puedes omitir -d dbname si esto está puesto en vuestro configuration


archivo.

4. Retomar el caso.

Cómo trabaja…
El addon instalación de módulo y la actualización son dos estrechamente relacionó
procesos, pero hay algunos diferencias importantes, cuando destacados en el próximos
dos secciones.

Addon Instalación
Cuándo tú insttodo un addon, Odoo comprueba su lista de disponible addons para un
uninstalled addon con el nombre suministrado. Él también controles para las dependencias
de aquel addon y, si cualquiera, él recursively instalarles antes de instalar el addon.

38
Capítulo 2

El proceso de instalación de un módulo solo consta de los pasos siguientes:

1. Si cualquiera, corrido el addon preinit gancho.


2. Carga las definiciones de modelo del código de fuente de la Pitón y actualizar la
estructura de base de datos si es necesario (ve Capítulo 4, Modelos de Aplicación,
for detalles).
3. Carga los archivos de dato del addon y actualizar los contenidos de base de datos si
es necesario
(Ve Capítulo 9, Dato de Módulo, para detalles).
4. Instalar el addon demo dato si demo el dato está habilitado en el caso.
5. Si cualquiera, corrido el addon postinit gancho.
6. Corrido un válidoation de las definiciones de vista del addon.
7. Si demo el dato está habilitado y la prueba está habilitada, corrido las
pruebas del addon (ve Capítulo 7, Depurando y Testaje Automatizado,
para detalles).
8. Actualización el estado de módulo en la base de datos.
9. Actualización las traducciones en elda tabase del addon traducciones
(ve Capítulo 11, Internacionalización, para detalles).

preinit Y postinit los ganchos están definidos en el __openerp__.py


Archiva utilizar el pre_init_gancho y correo_init_llaves de gancho,
respectivamente. El valor de la llave es el nombre of una Pitón funciona cuáles
tienen que ser definidos en el __init__.py Archivo del addon módulo. El
preinit (resp. postinit) El gancho se apellida con un cursor de base de datos
(resp. Un cursor de base de datos y un objeto de registro) y puede actuar
modificación en la base de datos a prepare (resp. Finaliza) la instalación de
módulo. Nota que estos no son correr cuándo el módulo está actualizado (
puedes utilizar pasos de migración para este, ve abajo).

Addon Actualización
Cuándo actualizas un addon, Odoo controles en su lista de disponible addon módulos para un
instaldirigió addon con el nombre dado. Él también controles para las dependencias inversas de
aquel addon (estos son el addons aquello depende de el actualizado addon), y, si cualquiera, él
recursively actualizarles.

El proceso de actualización de un solo addon el módulo consta de el following pasos:

1. Corrido el addon módulo pre pasos de migración, si cualquier (ve Capítulo 9, Dato
de Módulo, para detalles).
2. Carga las definiciones de modelo del código de fuente de la Pitón y actualizar la
estructura de base de datos si es necesario (ve Capítulo 4, Modelos de Aplicación,
para details).
3. Carga los archivos de dato del addon y actualizar los contenidos de base de datos si
es necesario (ve
Capítulo 9, Dato de Módulo para detalles).
4. Actualización el addon demo dato si demo el dato está habilitado en el caso.
5. Si cualquiera, corrido el addon pasos de migración del correo (ve Capítulo 9, Dato de
Módulo para detalles).

39
Dirige Odoo Casos de Servidor

6. Corrido una validación de las definiciones de vista del addon.


7. Si demo el dato está habilitado y la prueba está habilitada, corrido las
pruebas del addon (ve Capítulo 7, Depurando y Testaje Automatizado,
para detalles).
8. Actualización el estado de módulo en la base de datos.
9. Actualización las traducciones en la base de datos del addon
traducciones (ve Capítulo 11, Internacionalización, para detalles).
Nota que actualizando un addon módulo qué no es instalado nada en absoluto. Aun así,
instalando un addon módulo que es ya instalado reinstalls el addon, los cuales pueden tener
algunos unintended los efectos con algún dato archiva contener dato que está supuesto
para ser actualizado por el usuario y no actualizado durante la actualización de módulo
normal process (ve Utilizar el noupdate y forcecreate banderas en Capítulo 9, Dato de
Módulo). no hay ningún riesgo de error de la interfaz de usuario, pero esto puede pasar de la
línea de orden.

Allí ha más…
Ser prudente sobre la dependencia que maneja. Considerar un caso donde quieres tener el
addons venta, stock_de venta, y la venta_concreta instalado, con la venta_concreta
dependiendo de stock_de venta y stock_de venta que depende de venta. Para instalar
todo tres, sólo necesitas instalar la venta_concreta, cuando él recursively instalar el
dependerencies
Stock_de venta y venta . Para actualizar todo tres, necesitas actualizar venta, cuando
esto recursively actualizar el stock de venta de_dependencias inverso y la
venta_concreta .
Otra parte delicada es cuándo tú añade una dependencia a un addon que ya tiene una versión
instaldirigió. Para continuar con el ejemplo anterior, imagina que añades una dependencia en
accionario_dropshipping en la venta_concreta. Actualizando el addon la
venta_concreta no automáticamente instalar la dependencia nueva, tampoco pidiendo
la instalación de
Venta_specific. En esta situación, puedes conseguir error muy malo mensajes porque el
código de Pitón del addon no es exitosamente cargado pero el dato del addon y las mesas
de modelos en la base de datos son presentes. Para solucionar esto, necesitas parar el caso
y hombreually instalar la dependencia nueva.

Instalando addon módulos de GitHub


GitHub Es una fuente grande de tercer-partido addons. Mucho Odoo uso de socios GitHub
para compartir el addons mantienen internamente, y el Odoo Asociación Comunitaria (OCA)
en conjunto mantiene varios centenares de addons en GitHub. Antes de empezar para
escribir vuestro propio addon, ser seguro para comprobar que nada ya existe que podrías
utilizar cuando es o como punto de partida.
Esta receta te mostrará cómo para clonar el socio-proyecto de contacto de the OCA de
GitHub y hacer el addon módulos contiene disponible en vuestro caso.

40
Capítulo 2

Preparándose
Supone quieres cambiar las direcciones de manera están manejadas en vuestro caso; vuestro
cliente necesita un tercer campo además de Odoo dos (calle y calle2 ) para almacenar
direcciones.
Ciertamente podrías escribir vuestro propio addon para añadir un campo en res.Socio,
pero el asunto es un poco más delicado que parece si quieres la dirección para ser
correctamente formatted en facturas. Afortunadamente, alguien en un mailing la lista te
dices aproximadamente la calle_de dirección_del socio3 addon aquello está mantenido por
el OCA cuando parte del socio-proyecto de contacto.
Los caminos utilizaron en esta receta refleja el diseño propuesto en el Estandarizando
vuestra receta de diseño de directorio de caso.

How Para hacerlo…


Para instalar calle_de dirección_del socio3, seguir estos pasos:
1. Va al directorio de vuestro
proyecto: $ cd ~/odoo-
dev/mi-odoo

2. Clon la 9.0 rama del socio-proyecto de contacto en el src/ directorio: $


git clon --rama 9.0 \ https://github.com/oca/partner-
contacto.git src/Socio-contacto

3. Cambio el addons camino para incluir aquel directorio y actualizar el addons lista
de vuestro caso (ve recetas anteriores, Configurar el addons camino y Actualizar el
addon lista de módulos, de este capítulo).
4. Instalar el socio_añaderess_calle3 addon (ve la receta anterior anterior,
Instala y upgrade local addon módulos).

Cómo trabaja…
Todo el Odoo repositorios de código de Asociación Comunitarios tienen su addons contuvo
en subdirectorios separados, el cual es coherente con qué esexp ected por Odoo con
respecto a los directorios en el addons camino; por tanto, justo clonando el repositorio en
algún lugar y añadiendo que ubicación en el addons el camino es bastante.

Allí ha más…
Algunos maintainers seguir una aproximación diferente y tener uno addon módulo por
repositorio, viviendo en la raíz del repositorio. En aquel caso, necesitas crear un
directorio nuevo, el cual te añadirá al addons camino y clonar todo el addons de aquel
maintainer necesitas en este directorio. Recuerda para actualizar el addon lista de
módulos each tiempo añades un clon de repositorio nuevo.
41
Dirige Odoo Casos de Servidor

Aplicando cambios a addons


La mayoría de addons disponible en GitHub es subject de cambiar y no sigue las reglas que
Odoo Aplica para su liberación estable. Pueden recibir el bicho fija o trucajes, incluyendo
asuntos o peticiones de característica que te entregados, y estos cambios pueden introducir
base de datos schema cambios o actualizaciones en los archivos de dato y vistas. Esta
receta explica cómo para instalar el actualizó versiones.

Preparándose
Supone informaste un asunto con calle_de dirección_del socio3 y recibió una notificación
que el asunto estuvo solucionado en la revisión durada de la 9.0 rama del socio-proyecto
de contacto, querrás actualizar vuestro caso con esta versión más tardía.

Cómo para hacerlo…


Para aplicar una modificación de fuente a vuestro addon de GitHub, necesitas
actuar los pasos siguientes:
1. Parón el caso que utiliza que addon.
2. Marca una copia de seguridad si es un caso de producción (ve la receta Dirige
Odoo bases de datos de servidor en Capítulo 1, Installing el Odoo Entorno de
Desarrollo).
3. Va al directorio donde socio-el contacto estuvo
clonado: $ cd ~/odoo-dev/mi-odoo/src

4. Crear una etiqueta local para el proyecto de modo que puedes revert a
aquella versión en rotura de cosas del caso:
$ git checkout 9.0
$ git Etiqueta 9.0-antes de que-actualización-$(fecha --iso)

5. Conseguir la versión más tardía del


código de fuente: $ git atracción --
ff-único

6. Actualización la calle_de dirección_del socio3 addon en vuestras bases de datos


(ve la receta anterior Instala y upgrade local addon módulos).
7. Retomar el caso.
42
Capítulo 2

Cómo trabaja…
Esto es justo una aplicación sencilla de todas las recetas anteriores hemos visto;
conseguimos una versión nueva del addon y actualizamos él en nuestros casos.
Si git atracción --ff-único falla, puedes revert a la versión anterior que utiliza esta
orden:
$ git Reinicialización --duro 9.0-antes de que-actualización-$(fecha --
iso)

Entonces, puedes probar git atracción (sin --ff-único), el cual causará un fusionar,
pero esto significa tienes cambios locales en el addon.

Hay una entrada en la carta de Encuadres labeled


Upgrade módulos, but no trabaja para nuestro
propósito.

Ve también
Si las roturas de paso de la actualización, refiere al Actualizando Odoo de receta de Fuente
en Capítulo 1,
Instalando el Odoo Entorno de Desarrollo, para las instrucciones de recuperación.
Recuerda a siempre probar una actualización en una copia de una producción de base
de datos primero.

Aplicando y probando peticiones de


atracción propuesta
En el GitHub mundo, una Petición de Atracción (o PR para corto) es una petición hecha por un
desarrollador
Para el maintainers de un proyecto para incluir algunos desarrollos nuevos. Tal PR puede
contener un bicho fija o una característica nueva. Estas peticiones están revisadas y
probados antes de ser estirados en general rama.
Esta receta explica cómo para aplicar un PR a vuestro Odoo proyecto para probar una mejora
o un bicho fijan.

Preparándose
Cuando en la receta anterior, suponerte informó un asunto con calle_de dirección_del
socio3 y recibió una notificación que el asunto estuvo solucionado en una petición de
atracción, el cual no es todavía fusionado en la 9.0 rama del proyecto. El desarrollador te
preguntas para validar el fijar en PR #123. Necesitas to actualiza un caso de prueba con
esta rama.
No tendrías que probar fuera de tales ramas directamente en una base de datos de
producción, tan primero crear un entorno de prueba con una copia de la base de datos de
producción (ve Capítulo 1, Instalando el Odoo Entorno de Desarrollo, y C hapter 16,
Despliegue de Servidor).

43
Dirige Odoo Casos de Servidor

Cómo para hacerlo…


Para aplicar y probar fuera de un GitHub petición de atracción para un addon, necesitas actuar
los pasos siguientes:

1. Parón el caso.
2. Va al directorio donde socio-contactar wcuando clonó:
$ cd ~/odoo-dev/mi-odoo/src

3. Crear una etiqueta local para el proyecto de modo que puedes revert a aquella
versión en rotura de cosas del caso:
$ git checkout 9.0
$ git Etiqueta 9.0-antes de que-actualización-$(fecha --iso)

4. Atracción la rama de la petición de atracción. La manera más fácil es para utilizar


el número del PR, el cual tendría que haber sido comunicado a ti por el
desarrollador. En nuestro ejemplo, esto es el número de petición de la atracción
123:
$ git Atracción de origen de la atracción/123/cabeza

5. Actualización la calle_de dirección_del socio3 addon módulo en vuestra base de datos y


retomar the caso (ve la receta anterior, Instalando y upgrading local addon módulos).
6. Prueba la actualización—intenta reproducir vuestro asunto, o probar fuera de la
característica quisiste.

Si no trabaja, comentario en el PR página de GitHub, explicando qué hiciste y lo que did no


trabajar, de modo que el desarrollador puede actualizar el PR.
Si trabaja, dice tan en el PR página también; esto es una parte esencial del PR proceso de
validación y él solicitarán el fusionando en general rama. Puedes utilizar el texto :+1:, el cual
es rendered como "thumb arriba" icono, significando apruebas el PR.

Cómo trabaja…
Estamos utilizando un GitHub característica que habilita peticiones de atracción para ser
estirados por numera utilizar la atracción/nnnn/nombre de rama de la cabeza, donde
nnnn es el número del PR. El git orden de atracción fusionará el remoto brancho en el
nuestro, aplicando los cambios en nuestra base de código. Después de que esto,
actualizamos el addon módulo, prueba, e informe atrás al autor del cambio sobre cualquier
fracaso o éxito.
44
Capítulo 2

Allí ha más…
Puedes repetir paso cuatro para different peticiones de atracción en el mismo repositorio si
les quieres probar simultáneamente. Si eres realmente feliz con el resultado, puedes crear
una rama para mantener una referencia al resultado del aplicó cambios:
$ git checkout -b 9.0-hecho de encargo

Utilizando un different la rama ayudará recuerdas que no estás utilizando la versión


de GitHub, pero una costumbre un.
De entonces encima, si necesitas aplicar la revisión más tardía de la 8.0 rama de GitHub,
necesitarás estirar les sin utilizar --ff-único:
$ git Origen de atracción 9.0

45
3
Creando Odoo Módulos
En este capítulo, cubriremos los temas siguientes:

f Creando e instalando un nuevo addon el


f módulo que Completa el addon el módulo
f manifiesta
f Organizing El addon estructura de archivo
del módulo
f
Añadiendo Modelos
f
Añadiendo Elementos de
f
Carta y Ve Añadir Seguridad
de Acceso
Utilizando scaffold para crear un módulo

Introducción
Todos estos componentes que nosotros justo mencionados será dirigido en detalle en
capítulos más tardíos.

Ahora que we tiene un entorno de desarrollo y saber cómo para dirigir Odoo casos
de servidor y bases de datos, puedes aprender cómo para crear Odoo addon
módulos.
Nuestro objetivo principal aquí es para entender cómo un addon el módulo está
estructurado y el típico incremental workflow para añadir componentes a él.
Para este capítulo, estás esperado para tener Odoo instalado y para seguir las recetas
en
Capítulo 1, Instalando el Odoo Entorno de Desarrollo. Eres también esperado para
ser cómodo en descubrir e instalando extra addon módulos, cuando descritos en el
Capítulo 2, Dirigiendo Odoo Casos de Servidor, recetas.

47
Creando Odoo Módulos

Creando e instalando un nuevo addon


módulo
En esta receta, crearemos un módulo nuevo, lo hace disponible en nuestro Odoo
caso, e instalar it.

Preparándose
Necesitaremos un Odoo caso a punto para utilizar.

Si la primera receta en Capítulo 1, Instalando el Odoo Entorno de Desarrollo, estuvo seguido,


Odoo tendría que ser disponible en ~/odoo-dev/odoo. Para propósitos de explicación,
supondremos este location para Odoo, a pesar de que cualquiera otra ubicación de vuestra
preferencia podría ser utilizada.
También necesitaremos una ubicación para nuestro Odoo módulos. Para el propósito de esta
receta, utilizaremos un locales-addons directorio junto al odoo directorio, en ~/odoo-
dev/local-addons.

How Para hacerlo…


Los pasos siguientes crearán e instalar un nuevo addon módulo:

1. Cambio el directorio laborable en qué trabajaremos y crear el addons directorio


donde nuestro módulo hecho de encargo será colocado:
$ cd ~/odoo-dev
$ mkdir Local-addons

2. Escoger un technical nombre para el módulo nuevo y crear un directorio con aquel
nombre para el módulo. Para nuestro ejemplo utilizaremos mi_módulo:
$ mkdir Local-addons/mi_módulo

El nombre técnico de un módulo tiene que ser un identificador de


Pitón válido; tenga que empezar con una letra, y sólo contener
letras (preferentemente lowercase), números, y underscore
caracteres.

3. Marca el módulo de Pitón importable por añadir un __init__.py


Archivo: $ tocar local-addons/mi_módulo/__init__.py

4. Añadir un módulo mínimo manifiesta, para Odoo para detectarlo. Crear un


__abiertoerp__.py Archivo con esta línea:
{'Nombre': soyy módulo'}
5. Inicio vuestro Odoo el caso que incluye nuestro directorio de módulo en el
addons camino: $ odoo/odoo.py --addons-
camino=odoo/addons/,local-addons/

48
Capítulo 3

Si el --salvar la opción está añadida al Odoo command, el


addons el camino será salvado en el archivo de configuración.
Tiempo próximo empiezas el servidor, si ningún addons opción de
camino está proporcionada, esto será utilizado.

6. Marca el módulo nuevo disponible en vuestro Odoo caso; registro en a Odoo


utilizando admin, habilitar el Modo de Desarrollador en el Aproximadamente
caja, y en las Aplicaciones la carta superior selecciona Lista de Aplicaciones de la
Actualización. Ahora Odoo tendría que saber sobre nuestro Odoo módulo.
7. Seleccionar la carta de Aplicaciones en el superior y, en la barra de búsqueda en
el derecho superior, eliminar el default filtro de Aplicaciones y buscar
mi_módulo. Clic on su Instalar el botón y la instalación serán concluidos.

Cómo trabaja…
Un Odoo el módulo es un directorio conteniendo archivos de código y otras ventajas. El
nombre de directorio utilizó es el nombre técnico del módulo. La llave de nombre en el
módulo manifiesta es su título.

TÉl __openerp__.py El archivo es el módulo manifiesta. Contiene un diccionario de Pitón con


información sobre el módulo, los módulos depende de, y los archivos de dato que lo cargará.
En el ejemplo, un mínimo manifiesta el archivo estuvo utilizado, pero en módulos reales,
nosotros will quiere añadir unas cuantas otras llaves importantes. Estos están hablados
en la receta próxima, Completando el módulo manifiesta.
El directorio de módulo tiene que ser Pitón -importable, así que también necesita tener un
__init__. py Archivo, incluso si es vacío. Para cargar un módulo, el Odoo el servidor lo
importará. Esto causará el código en el __init__.py Archivo para ser ejecutado, así que
trabaja como un punto de entrada para correr el módulo
Código de pitón. Debido a este, normalmente contenga declaraciones de importación para
cargar el módulo
Archivos de pitón y submodules.

Los módulos pueden ser instalados directamente de la línea de orden que utiliza el --init,
o -i , opción. Antiguamente, tuvimos que utilizar la Lista de Módulo de la Actualización
para hacerlo disponible al Odoo caso. Aun así, en este momento, esto está hecho
automáticamente cuándo el --init or --la actualización está utilizada de la línea de orden.

Completando el addon el módulo manifiesta


El manifestar es una pieza importante para Odoo módulos. Contiene información importante
aproximadamente lo y declara el dato archiva que tendría que ser cargado.
49
Creating Odoo Módulos

Preparándose
Tendríamos que tener un módulo para trabajar con, ya conteniendo un __openerp__.py
Manifiesta archivo. Puedes querer seguir la receta anterior para proporcionar tal módulo
para trabajar con.

Cómo para hacerlo…


Añadiremos un manifestar archivo y unn icono a nuestro addon módulo:

1. Para crear un manifestar archivo con las llaves más pertinentes, editar el módulo
__openerp__. py Archivo para parecer esto:
# -*- Codificación: utf-8 -*-
{
'Nombre': "Título",
Esummary': "Corto subtitle frase",
'descripción': """Largo description""",
'autor': "Vuestro nombre",
'Licencia': "AGPL-3",
'Sitio web': "http://www.example.com",
'categoría': 'Uncategorized',
'versión': '9.0.1.0.0',
'Depende': ['base'],
'dato': ['vistas.xml'],
'demo': ['demo.xml'],
}

2. Para añadir un icono para el módulo, escoger un PNG imedad para


utilizar y copiarlo a icono/de descripción/estática.png .

Cómo trabaja…
La primera línea, conteniendo codificación: utf-8, es necesario para Pitón para
procesar el contenido de archivo como Unicode UTF-8. De este modo, podemos utilizar no-
ASCII caracteres en el manifestar.
El remainincontenido de g es un diccionario de Pitón regular , con llaves y valores. El
ejemplo manifiesta utilizamos contiene las llaves más pertinentes:
f Nombre: Esto es el título para el módulo.
f Resumen: Esto es el subtitle con una descripción de una líneas.
fDescripción: Esto is una descripción larga, escrito en texto sencillo o
ReStructuredText(RST) formato. Es normalmente rodeado por triple cita, utilizado
en Pitón para delimitar multiline textos. Para un RST quickstart referencia, http de
visita://docutils.
sourceforge.net/docs/user/rst/quickstart.html.
50
Capítulo 3

fAutor: Esto es una cuerda con el nombre de los autores. Cuando hay más de
uno,es práctica común para utilizar una coma para separar sus nombres, pero
nota que lo todavía tendría que ser una cuerda, no una lista de Pitón.
fLicencia: Esto es el identificador para la licencia bajo qué el módulo está
hechadisponible. Está limitado a un predefined lista, y la mayoría de opción
frecuente es AGPL-3. Otras posibilidades incluyen LGPL-3, Otro OSI
licencia aprobada, y Otro.
Propietario.
fSitio web: Esto es un URL las personas tendrían que visitar para saber más
sobre el módulo o losautores.
fCategoría: Esto suele organizar módulos en áreas de interés. La lista de la categoría
estándar nombra disponible puede ser visto en https://github.com/odoo/
odoo/blob/Maestro/openerp/addons/dato/de módulo/de módulo_de
base.xml. Pero
Es también posible de definir otros nombres de categoría nuevos aquí.
fVersión: Esto es los módulos ' version números. Pueda ser utilizado por el Odoo
tiendade aplicación para detectar versiones más nuevas para módulos instalados.
Si el número de versión no empieza con el Odoo versión de objetivo (por ejemplo,
8.0), sea automáticamente añadió. No obstante, sea más informativo si
explícitamente declaras el Odoo versión de objetivo, por ejemplo, utilizando
8.0.1.0.0 o 8.0.1.0 en vez de 1.0.0 o 1.0.
fDepende: Esto es una lista con los nombres técnicos de los módulos directamente
dependeencima. Si ninguno, al menos tendríamos que depender de la base
module. No olvida para incluir cualquier módulo que define XML IDs, Vistas, o
Modelos referenced por este módulo. Aquello asegurará que ellos todos cargan en
el orden correcto, evitando duro-a-depurar errores.
fDato: Esto es una lista de caminos relativos a los archivos de dato a load con
instalación de móduloo upgrade. Los caminos son relativos al directorio de raíz del
módulo. Normalmente, estos son
XML y CSV archivos, pero es también posible de tener YAML archivos de dato. Estos
están hablados a fondo en Capítulo 9, Dato de Módulo.
f demo: Esto est liste de caminos relativos a los archivos con dato de manifestación para
cargar.
Estos sólo serán cargados si la base de datos estuvo creada con la bandera de
Dato de la Manifestación habilitó.

La imagen que está utilizado como el icono de módulo es el PNG archivo en icono/de
descripción/estática. png.

Odoo Está esperado para tener cambios significativos entre versiones


importantes, tan los módulos construyeron para uno la versión
importante probablemente puede a no ser compatible con la versión
próxima sin conversión y trabajo de migración. Debido a este, es
importante de ser seguro about un módulo Odoo versión de objetivo
antes de instalarlo.
51
Creando Odoo Módulos

Allí ha más
En vez de habiendo la descripción larga en el módulo manifiesta, es posible de tener él en
su archivo propio. Desde entonces versión 8.0, pueda ser reemplazado por un README
archivo, con cualquier un .txt, .rst, o un .md (Markdown) Extensión. Otherwise, incluir
un índice/de descripción.html Archivo en el módulo.
Esta descripción de HTML override una descripción definida en el manifestar archivo.

hay unos cuantos más llaves que are frecuentemente utilizó:

fAplicación: Si esto esCierto, el módulo está listado como una aplicación.


Normalmente, esto estáutilizado para el módulo central de una área funcional.
fEl coche_instala: Si esto esCierto, indica que esto es un "módulo" de
pegamento , el cual es aliadoautomáticoinstalado cuando todas sus
dependencias están instaladas.
finstallable: Si esto esCierto(el default valor), indica que el módulo
esdisponible para instalación.

Organizando el addon estructura de archivo


del módulo
Un addon el módulo contiene archivos de código y otras ventajas como XML archivos e
imágenes. Para la mayoría de estos archivos, somos libres de escoger dónde para colocarles
interior el directorio de módulo.
Aun así, Odoo utiliza algunas convenciones en la estructura de módulo, así que es
aconsejable de seguirles.

Preparándose
Estamos esperar para tener un addon directorio de módulo con único el __init__.py Y
__openerp__.py Archivos.

Cómo para hacerlo…


Para crear el esqueleto básico para el addon módulo:

1. Crear los directorios para archivos


de código: $ cd camino/a/mi-
módulo
$ mkdir Modelos
$ Tacto models/__init__.py $
mkdir Controladores
52
Capítulo 3
$ Controladores de
tacto/__init__.py $ mkdir Vistas
$ mkdir
Seguridad $
mkdir dato
$ mkdir demo
$ mkdir i18n
$ mkdir -p Descripción/estática

2. Editar el módulo superior __init__.py Archivo de modo que el bacalaoe en los


subdirectorios está cargado:
# -*- Codificación: utf-8 -*-
De . Modelos de
importación de .
Controladores de
importación

Esto nos tendría que conseguir empezado con una estructura que contiene el más utilizó
directorios, similares a este un:
.
├── __init__.py ├──
__openerp__.py

├── controllers
│ └── __init__.py
├── Dato
├── i18n
├──
modelos
│ └── __init__.py
├── Seguridad
├── Estático
│ └── Vistas └──
de descripción
53
Creando Odoo Módulos

Cómo trabaja…
Para proporcionar algún contexto, un Odoo addon el módulo puede tener tres tipos de
archivo:

fElcódigo de Pitónestá cargado por__init__.pyArchivos,


dondeel.pyArchivos y subdirectoriosde código están importados. Los
subdirectorios que contienen Pitón de código, en vuelta, necesidad su propio
__init__.py
fEl dato archivaaquello es para ser declarado endatoy demollaves
del__openerp__.py El módulo manifiesta para ser cargado. Estos son
normalmente XML y CSV archivos para la interfaz de usuario, fixture dato, y dato
de manifestación.
fVentajas de webcomo código de Javascript y bibliotecas, CSS, y QWeb/plantillas de
HTMLtambién juegan una parte importante. Allí está declarado a través de un archivo
de XML que extiende las plantillas maestras para añadir estas ventajas al cliente de
web o páginas de sitio web.

El addon los archivos son para ser organizados en estos directorios:

fLos modelos/contiene el backend archivos de código, creating los Modelos y su


lógicaempresarial. Un archivo por Modelo está recomendado, con el mismo
nombre como el modelo, por ejemplo, library_book.py para la
biblioteca.Modelo de libro. Estos están dirigidos a fondo en Capítulo 4, Modelos
de Aplicación.
fLas vistas/contiene los XML archivos para la interfaz de usuario, con las
acciones, formas, listas,y tan encima. Cuando con modelos, está aconsejado para
tener uno archiva por modelo. Filenames Para plantillas de sitio web están esperadas
para acabar con el _sufijo de plantilla. Backend Las vistas están explicadas en
Capítulo 8, Backend Vistas, y Vistas de sitio web están dirigidas en
Capítulo 14, Desarrollo de Sitio de Web de CMS.
f El dato/ contiene otros archivos de dato con módulo dato inicial. Archivos de dato
están explicados en
Capítulo 9, Dato de Módulo.
fdemo/Contiene archivos de dato con dato de manifestación, útil para
pruebas, entrenando o evaluación de módulo.
f i18n/ es donde Odoo buscará la traducción .Tarro y .po Archivos. Ve
Capítulo 11, Internacionalización, para más detalles. Estos archivos no
necesitan para ser mencionados en el manifestar archivo.
fLa seguridad/contiene el dato archiva definir listas de control del acceso,
normalmente unir.Modelo.Acceso.csv Archivo, y posiblemente un archivo de
XML para definir Grupos de acceso y
Reglas récord para seguridad de nivel de la fila. Ve Capítulo 10, Seguridad de
Acceso, para más detalles en este.
fLos controladores/contiene los archivos de código para los controladores
de sitio web, para los módulos queproporcionan que clase de característica.
Controladores de web están cubiertos en Capítulo 13, Desarrollo de Servidor de
la Web.

54
Capítulo 3

fEstático/es donde todas ventajas de web están esperadas para ser colocados.
A diferencia de otros directorios,este nombre de directorio no es justo una
convención, e interior de archivos únicos pueda ser hecho disponible para el Odoo
páginas web. No necesitan para ser mencionados en el módulo manifiesta, pero
tendrá que ser referido a en la plantilla de web. This Está hablado con más detalle
en Capítulo 14, Desarrollo de Sitio web del CMS.

Cuándo añadiendo archivos nuevos a un módulo, no olvida para


declararles tampoco en el __openerp__.py (Para archivos de datos)
o __init__.py (Para archivos de código); otherwise, aquellos archivos
serán ignorados und no será cargado.

Añadiendo modelos
Los modelos definen las estructuras de dato para ser utilizados por nuestras aplicaciones
empresariales. Estos espectáculos de receta cómo para añadir un modelo básico a un
módulo.
Utilizaremos un ejemplo de biblioteca de libro sencillo para explicar esto; queremos un
modelo para representar books. Cada libro tiene un nombre y una lista de autores.

Preparándose
Tendríamos que tener un módulo para trabajar con. Si seguimos la primera receta en este
capítulo, tendremos un vacíos mi_módulo. Utilizaremos que para nuestra explicación.

Cómo para hacerlo…


Para añadir un nuevo Model, añadimos un archivo de Pitón que lo describe y entonces
upgrade el addon módulo
(O instalarlo, si no sea ya hecho). Los caminos utilizaron es relativo a nuestro addon
ubicación de módulo (por ejemplo, ~/odoo-dev/local-addons/mi_módulo/):
1. Añadir un archivo de Pitón al módulo, modelos/library_book.py, con el código
siguiente:
# -*- Codificación: utf-8 -*-
De openerp modelos de importación,
clase de campos
LibraryBook(modelos.Modelo):
_Nombre = 'biblioteca.Libro'
Campos = de nombre.Char('Título',
requerido=Cierto) campos_de liberación = de la
fecha.Fecha( esarrendamiento Dcomió')
autor_ids = campos.Muchos2muchos( ess.Socio',
Cuerda='Autores')
2. Añadir un archivo de inicialización de la Pitón con archivos de código
para ser cargados por los modelos de módulo/__init__.py, con el
código siguiente:
De . Libro de biblioteca_de la importación

55
Creando Odoo Módulos

3. Editar el archivo de inicialización de Pitón de módulo para tener el directorio/


de modelos cargado por el módulo:
De . Modelos de importación

4. Upgrade El Odoo módulo, cualquiera de la línea de orden o de la carta de


aplicaciones en la interfaz de usuario. Si miras estrechamente en el registro de
servidor mientras upgrading el módulo, tendrías que ver esta línea:
openerp.Módulos.Módulo: módulo mi_módulo: creando o
actualizando mesas de base de datos

Después de que esto, la biblioteca nueva.Modelo de libro tendría que ser disponible en nuestro
Odoo caso. Si tenemos las herramientas técnicas activand, podemos confirmar que por mirarlo
arriba en los encuadres | Técnicos
| Modelos de Estructura | de la base de datos.

Cómo trabaja…
Nuestro primer paso era para crear un archivo de Pitón donde nuestro módulo nuevo estuvo
creado.

Odoo Los modelos son objetos derivó del Odoo clase de Pitón del Modelo.

Cuándo un modelo nuevo está definido, es también añadido a un registro de modelo central.
Esto lo hace más fácil para otros módulos a modificaciones de marca más tardía a él.
Los modelos tienen unos cuantos atributos genéricos prefijaron con un underscore. El más
importante uno es nombre _, providing un identificador interno único para ser utilizado
durante el Odoo caso.
Los campos de modelo están definidos tan atributos de clase. Empezamos definir el campo
de nombre del Char tipo. Es conveniente para modelos para tener este campo, porque por
default, está utilizado como la descripción récord cuándo referenced de otros modelos.
También utilizamos un ejemplo de un campo relacional, autor_ids. Define un muchos -
a-mucha relación entre Libros de Biblioteca y los socios — un libro puede tener
muchos autores y cada autor pueden tener muchos libros.
Allí ha mucho más para decir sobre modelos, y serán cubiertos en más profundidad en
Capítulo 4,
Modelos de aplicación.

Luego, tenemos que hacer nuestro módulo consciente de este archivo de Pitón nuevo. Esto
está hecho por el __init__. py Archivos. Desde entonces colocamos el código dentro
del subdirectorio/ de modelos, necesitamos el anteriores init archivo para
importar aquel directorio, el cual tiene que en girar contener otro init el archivo
importador cada cual de los archivos de código allí (justo uno en nuestro caso).
Cambios a Odoo los modelos están activados por upgrading el módulo. El Odoo el servidor
manejará la traducción de la clase de modelo a cambios de estructura de la base de datos.
56
Capítulo 3

A pesar de que ningún ejemplo está proporcionado aquí, la lógica empresarial también puede ser
añadida a estos archivos de Pitón, cualquiera por añadir métodos nuevos alM odel clase, o por
extender existiendo métodos, como crear() o escribir() . Esto está dirigido en Capítulo 5,
Desarrollo de Lado de Servidor Básico.

Añadiendo Elementos de Carta y Vistas


Una vez tenemos Modelos para nuestras necesidades de estructura del dato, queremos una
interfaz de usuario para nuestro nosers para interaccionar con ellos. Estas complexiones de
receta en el Modelo de Libro de la Biblioteca de la receta anterior y añade un elemento
de carta para mostrar una interfaz de usuario que presenta lista y Vistas de forma.

Preparándose
El addon el módulo que implementa la biblioteca.Modelo de libro, proporcionado en la receta
anterior, está necesitado. Los caminos utilizaron es relativo a nuestro addon ubicación de módulo
(por ejemplo, ~/odoo-
dev/Local-addons/mi_módulo/).

Cómo para hacerlo…


Para añadir una vista, añadiremos un archivo de XML con su definición al módulo. Desde
entonces es un nuevo Model, también tenemos que añadir una opción de carta para el
usuario para ser capaz de accederlo.
Ser consciente que la secuencia de los pasos siguientes es pertinente, desde entonces
algunas referencias de uso a
IDs Definió en pasos anteriores:

1. Crear el archivo de XML para añadir el dato graba describir la biblioteca de vistas
de interfaz/ de usuario_libro.xml:
<?xml Versión="1.0" codificando="utf-
8"?> <openerp>
<Dato>
<!-- Registros de datos van
aquí --> </datos>
</openerp>

2. Añadir el archivo de dato nuevo al addon el módulo manifiesta, __openerp__.py


Por añadirlo a la biblioteca/de vistas_book.xml:
# -*- Codificación: utf-8 -*-
{
'Nombre': "Libros de
Biblioteca", esummary':
"Dirigir vuestros libros",
'depende': ['base'],
'Dato': ['libro/de biblioteca_de las vistas.xml'],
}

57
Creando Odoo Módulos

3. Añadir la Acción que abre las Vistas en el library_book.xml archivo:


<Ventana_de acto
id="nombre_de acción_de
libro" de biblioteca="la
biblioteca Reserva"
res_biblioteca="de
modelo.Libro" />

4. Añadir el elemento de carta al libro_de biblioteca.xml Archivo, haciéndolo


visible a los usuarios:
<menuitem id="Nombre_de
carta_de libro" de
biblioteca="libro" de
biblioteca="de acción_de
Biblioteca_padre" de
acción=""
Secuencia="5" />

Si pruebas y upgrade el módulo ahora, tendrías que ser capaz de ver una opción de
carta superior nueva ( podrías necesitar a refresh vuestro navegador de web). Clicking
Encima tenga que trabajar y abrirá las vistas para Biblioteca Reserva aquello es
automáticamente generated por el servidor.

5. Añadir una vista de forma hecha de encargo al libro_de biblioteca.xml Archivo:


<Récord id="forma_de vista_de libro_de biblioteca"
modelo="ir.ui.Nombre"> <de nombre de campo="de
vista">campo de Forma de Libro</de Biblioteca>
<Biblioteca de modelo="de nombre">de
campo.Nombre</de campo> <de campo de
libro="tipo" de arco="xml">

<Forma>
<Grupo>
<Nombre de nombre="del campo"/>
<Autor de nombre="del campo_ids"
widget="muchos2mucho_grupo"/> </de etiquetas>
<Grupo>
<Liberación de fecha="de
nombre_de campo"/> </grupo>
</Forma>

</Campo>
</Récord>

58
Capítulo 3

6. Añadir un Árbol hecho de encargo (Lista) vista al library_libro.xml Archivo:


<Récord id="árbol_de vista_de libro_de biblioteca"
modelo="ir.ui.Nombre"> <de nombre de campo="de
vista">campo de Lista de Libro</de Biblioteca>
<Biblioteca de modelo="de nombre">de
campo.Nombre</de campo> <de campo de
libro="tipo" de arco="xml">

<Árbol>
<Nombre de nombre="del campo"/>
<Liberación de fecha="de
nombre_de campo"/> </tree>

</Campo>
</Récord>

7. Añade opciones de Búsqueda hecha de encargo al libro_de biblioteca.xml


Archivo:
<Récord id="búsqueda_de vista_de libro_de biblioteca"
modelo="ir.ui.Nombre"> <de nombre de campo="de
vista">campo de Búsqueda de Libro</de Biblioteca>
<Biblioteca de modelo="de nombre">de
campo.Nombre</de campo> <de campo de
libro="tipo" de arco="xml">

<Búsqueda>
<Campo de nombre="de
nombre"/> <de campo
autor="de nombre_ids"/>
<cuerda de filtro="Ningún
Autor"
Ámbito="[('autor_ids','=',Falso)]"/>
</Búsqueda>

</Campo>
</Récord>

Cómo trabaja…
En el nivel bajo, la interfaz de usuario está definida por los registros almacenaron en
Modelos especiales. Los primeros dos pasos crean un archivo de XML vacío para definir los
registros de ser cargados y entonces añadirles a la lista del módulo de los datos archiva para
ser instalados.
Archivos de dato pueden ser anywhere dentro del directorio de módulo, pero la convención
es para el usuario intercara para ser definida dentro de un subdirectorio/ de vistas que
utiliza nombres de archivo después del Modelo la interfaz es para. En nuestro caso, la
biblioteca.Interfaz de libro es en el libro/de biblioteca_de las vistas. xml
Archivo.

59
Creando Odoo Módulos

El paso próximo es para definir un Window Acción para mostrar la interfaz de usuario en
general área del cliente de web. La Acción tiene un Modelo de objetivo definido por
res_modelo y pone el título para mostrar al usuario que utiliza nombre. Estos son justo
los atributos básicos. Apoya atributos adicionales, giving mucho más control de cómo las
Vistas son rendered, como qué Vistas son para ser mostrados, añadiendo filtros en los
registros disponibles, o poniendo default valores. Estos están hablados en detalle en
Capítulo 8, Backend Vistas.

En general, registros de dato son defined utilizando <una etiqueta> récord, pero en
nuestro ejemplo, la Ventana
La acción estuvo definida utilizando la etiqueta_de ventana <> del acto. Esto es un atajo
para crear registros para el ir.Acciones.Modelo_de ventana del acto, donde
Acciones de Ventana están almacenadas.

De modo parecido, elementos de carta están almacenados en el ir.ui.Modelo de carta,


pero una comodidad <menuitem> etiqueta de atajo es disponible y estuvo utilizado.
Estos son los elementos de carta ' los atributos principales utilizaron aquí:

f Nombre: Esto es el texto de elemento de la carta para ser mostrado.


f Acción: Esto es el identificador de la acción para ser ejecutada. Utilizamos el ID del
Acción de ventana creada en el paso anterior.
fSecuencia: Esto suele puesto el orden en qué los elementos de carta del mismo
nivelestán presentados.
fPadre: Esto es el identificador para el elemento de carta del padre. Nuestro
elemento de carta del ejemplo hubono padre, significando que es para ser
mostrado en la parte superior de la carta.
Al llegar a este punto, nuestro módulo puede mostrar un elemento de carta, y clicking
encima abre Vistas para el
Modelo de Libros de la biblioteca. Desde entonces nada concreto está puesto en la
Acción de Ventana, el default es a dispponer una Lista (o Árbol) vista y una vista de forma.
No hemos definido cualquiera de estas Vistas, tan Odoo automáticamente les creará encima
la mosca.
Aun así, seguramente querremos controlar cómo nuestra mirada de Vistas, tan en el
próximo dos pasos, una forma y una vista de árbol están creadas.

Ambas Vistas están definidas con un registro en el ir.ui.Modelo de vista. Los atributos
utilizamos es como sigue:
fNombre: Esto es un título identificando esta vista. Es frecuente de ver el XML ID
repitióaquí, pero perfectamente pueda ser un título legible más humano.
f Modelo: Esto es el identificador interno del modelo de objetivo, cuando definido en su
_Atributo de nombre.
fArco: Esto es la arquitectura de vista , donde su estructura es de hecho definió.
Esto esdonde tipos diferentes de Ver diferir de cada otro.
60
Capítulo 3

Vistas de forma están definidas con un elemento <de forma> superior, y su tela es una
verja de dos columnas . Dentro de la forma, <elementos> de grupo suelen verticalmente
componer campos. Dos resultado de grupos en dos columnas con campos, aquello está
añadido utilizando el <campo> element. Los campos utilizan un default widget según su
tipo de dato, pero un concreto widget puede ser utilizado con la ayuda del widget
atributo.

Vistas de árbol son más sencillas; están definidos con un elemento <de árbol>
superior que contiene <elementos> de campo para las columnas para ser mostradas.
Finalmente, añadimos una vista de Búsqueda para expandir la opción de búsqueda en la
caja en el derecho superior. Dentro de la <búsqueda> etiqueta de nivel superior, podemos
tener <campo> y elementos <> de filtro. Elementos de campo son campos adicionales que
puede ser buscado de la caja. Filter Los elementos son predefined el filtro condiciona que
puede el activado con un clic.

Utilizando scaffold para crear un módulo


Cuándo creando un nuevo Odoo módulo, hay algunos boilerplate que necesidades de ser
instaladas. Para ayudar rápidamente empezando módulos nuevos, Odoo proporciona el
scaffold orden.

Los espectáculos de receta cómo para crear un módulo nuevo que utiliza el scaffold
orden, el cual pondrá en colocar un esqueleto de los directorios de archivos para utilizar.

Preparándose
Necesitamos Odoo instalados y un directorio para nuestros módulos hechos de encargo.

Supondremos que Odoo está instalado en ~/odoo-dev/odoo y nuestros módulos hechos


de encargo serán ~en /odoo-dev/locales-addons.

Cómo para hacerlo…


El scaffold la orden está utilizada de la línea de orden:

1. Cambio el directorio laborable a dónde querremos nuestro módulo para ser. Esto
puede ser quénunca directorio escoges, pero dentro de un addons camino para ser
útil. Siguiendo las elecciones de directorio utilizaron en la receta anterior, tenga
que ser como sigue:
$ cd ~/odoo-dev/Local-addons

2. Escoger un nombre técnico para el módulo nuevo y utilizar el scaffold orden para
crearlo. Para nuestro ejemplo, escogeremos mi_scaffolded:
$ ~/odoo-dev/odoo/odoo.py scaffold Mi_scaffolded
3. Editar el __openerp__.py default El módulo manifiesta proporcionado y
cambiar los valores pertinentes. Seguramente quieres al menos cambiar el
módulo title en la llave de nombre.
61
Creando Odoo Módulos

Esto es cómo el generado addon el módulo tendría que parecer:

$ Árbol mi_scaffolded
mi_scaffolded
├── controllers.py
├── demo.xml
├── __init__.py
├── models.py
├── __openerp__.py
├── Seguridad
│ └── ir.Modelo.Acceso.csv
└── Plantillas.xml

Cómo trabaja…
El scaffold la orden crea el esqueleto para un módulo nuevo basado en una plantilla.
Por default, el módulo nuevo está creado en el directorio laborable actual, pero podemos
proporcionar un directorio concreto donde to crear el módulo, pasándolo cuando un
parámetro adicional.
Por ejemplo:

$ ~/odoo-dev/odoo/odoo.py scaffold Mi_módulo ~/odoo-dev/local-addons

Un default la plantilla está utilizada pero una plantilla de tema es también


disponible, para tema de sitio web authoring. Para escoger un specific plantilla, el -t la
opción puede ser utilizada. Somos también dejados para utilizar un camino para un
directorio con una plantilla.
Esto significa que podemos utilizar nuestras plantillas propias con el scaffold orden. El
construido-en los temas pueden ser utilizados como guía, y pueden ser encontrados en el
Odoo subdirectorio
./openerp/cli/Plantillas. Para utilizar nuestra plantilla propia, podríamos utilizar
algo así:
$ ~/odoo-dev/odoo/odoo.py scaffold -t Camino/a/plantilla mi_módulo

Allí ha más…
Desafortunadamente, el default la plantilla no adhiere a la corriente Odoo directrices. Podríamos
crear nuestra plantilla propia por copiar el default un, en odoo/openerp/cli/plantillas/
default/, y modificando a traje mejor la estructura descrita en el Organizando la receta de
estructura de archivo de módulo. Una orden similar a esto nos podría conseguir empezado en
aquel:
$ cp -r ~/odoo-dev/odoo/openerp/cli/Plantillas/default ~/odoo-dev/plantilla
Más tarde, podemos utilizar él con la orden siguiente:

$ ~/odoo-dev/odoo/odoo.py scaffold -t ~/odoo-dev/Plantilla mi_módulo

62
4
Modelos de
aplicación
En este capítulo, cubriremos los temas siguientes:
fff
f

f

f

f

f

f

f

f

f

f


esentación de Modelo y el orden que Añade
D
campos de dato a un Modelo
e
Utilizando un campo de flotador con
f
configurable la precisión que Añade un campo
i
monetario a un Modelo
n
Adding Campos relacionales a un Modelo
i
Añadiendo una jerarquía a un Modelo
e
Añadiendo validaciones de constreñimiento a un Modelo
n
Añadiendo computó campos a un Modelo
d
Exponiendo Relacionó los campos almacenaron
o
en otros modelos que Añaden las relaciones
l
dinámicas que utilizan campos de Referencia
a
Añadiendo características a un Modelo que utiliza la
r
herencia que Utiliza Modelos Abstractos para
e
características de Modelo reutilizable
p
Utilizando herencia de Delegación para copiar características a
r otro Modelo

Introducción
Para concisely conseguir el punto a través de, las recetas en esta marca de capítulo
adiciones pequeñas a un existiendo addon módulo. Escogimos utilizar el módulo creado por
las recetas en Capítulo 3, Creando Odoo Módulos. A mejor seguir los ejemplos aquí, tendrías
que tener aquel módulo creado y a punto para utilizar.

63
Modelos de aplicación

Definiendo el Model representación y orden


Los modelos tienen los atributos estructurales que definen su comportamiento. Estos
están prefijados con un underscore y la mayoría de importantes es _nombre, el cual
define el identificador global interno para el Modelo.
hay dos otros atributos nosotros can uso. Uno para poner el campo utilizado como
representación, o título, para los registros, y otro para poner el orden están presentados en.

Preparándose
Esta receta supone que tienes un caso a punto con mi_módulo , cuando descrito en
Capítulo 3, Creating Odoo Módulos.

Cómo para hacerlo…


El mi_caso de módulo ya tendría que contener un archivo de Pitón llamó
biblioteca/de modelos_ book.py, el cual define un modelo básico. Lo editaremos
para añadir una clase nueva-atributo de nivel después de que _nombre:
1. Para añadir un humano-título amistoso al modelo, añadir el siguiente:
_Descripción = 'Libro de Biblioteca'

2. Para tener los registros ordenaron primero por default de más nuevos a
más viejos y entonces por título, añadir el siguiente:
_Orden = 'liberación_de fecha desc, nombre'

3. Para utilizar el campo_de nombre corto como la representación récord, undd el


siguiente:
_rec_Nombre = hort_nombre'
Campos_de nombre = corto.Char( Eshort Título')

Cuándo estamos hacer, nuestro library_book.py el archivo tendría que parecer esto:
# -*- Codificación: utf-8 -*-
De openerp modelos de importación,
clase de campos
LibraryBook(modelos.Modelo):
_Nombre = 'library.Libro'
_descripción = 'Libro de
Biblioteca' _orden =
'liberación_de fecha desc,
nombre' _rec_nombre'hort_nombre'
Campos = de nombre.Char('Título',
requerido=Cierto) campos_de nombre =
corto.Char( Eshort Título') campos_de
liberación = de la fecha.Fecha( esFecha de
arrendamiento')
Autor_ids = campos.Muchos2mcualquier( ess.Socio',
cuerda='Autores')

64
Capítulo 4

Tenemos que entonces upgrade el módulo para tener estos cambia activados en Odoo.

Cómo trabaja…
El primer paso añade un título de descripción más amistoso a la definición del modelo. Esto no es
obligatorio, pero puede ser utilizado por algún addons. Para caso, está utilizado por la
característica de seguir en el correo addon módulo para el texto de notificación cuándo un
registro nuevo está creado. Para más detalles, ve
Capítulo 12, Automatización y Workflows.

Por default, Odoo ordena el records utilizando el interno id valor. Pero esto puede ser
cambiado para utilizar los campos de nuestra elección por proporcionar un _atributo de
orden con una cuerda que contiene una coma-lista separada de nombres de campo. Un
nombre de campo puede ser seguido con el desc palabra clave para tenerlo ordenada en
orden inverso.
Los campos únicos almacenaron en la base de datos puede ser utilizada. No-almacenó
computó los campos no pueden soler registros de clase.

La sintaxis para la _cuerda de clase es similar a ORDEN


de SQL POR cláusulas, a pesar de que está desnudado
abajo. Para caso, cláusulas especiales such como NULLS
PRIMERO no es dejado.

Registros de modelo tienen una representación utilizada cuándo son referenced de otros
registros. Por ejemplo, un usuario_id campo con el valor 1 representa el usuario de
Administrador. Cuándo mostrado en una vista de forma, seremos mostrados el noser
nombre más que la base de datos ID. Por default, el campo de nombre está utilizado. De
hecho, aquello es el default valor para el _rec_atributo de nombre, y es por eso que
es conveniente de tener un campo de nombre en nuestros Modelos.

Si ningún campo de nombre existe en el modelo, un representatel ión está generado con el
modelo e identificadores récord, similares a (biblioteca.Libro, 1).

Allí ha más…
La representación récord es disponible en un nombre de exhibición_mágico el campo
computado añadió automáticamente a todos los modelos desde entonces versión 8.0.
Sus valores están generados ucantar el nombre de método del Modelo_consigue(),
el cual era ya en existencia en anterior Odoo versiones.

Su default la implementación utiliza el _rec_atributo de nombre. Para representaciones


más sofisticadas, podemos override su lógica. Este método tiene que regresar una lista de
tuples con dos elementos: el ID del récord y el Unicode representación de cuerda para que
así conste.
65
Modelos de aplicación

Por ejemplo, para tener el título y su fecha de liberación en la representación, como Moby
Dick (1851-10-18), podríamos define el siguientes:
def El
nombre_consigue
(self):
resultado = []
Para récord en self:

resultado.Anexa(

(record.id,

u"%s (%s)" % (record.name, registro.La


fecha_liberada)
))
Resultado de regreso

Nota que utilizamos un Unicode cuerda mientras construyendo la representación


récord, u"%s (%s)". Esto es importante de evitar errores, en caso encontramos no-
ASCII caracteres.

Añadiendo campos de dato a un modelo


Los modelos están significados para almacenar dato, y este dato está estructurado en
campos. Aquí, aprenderemos sobre los varios tipos de datos que puede ser almacenado en
campos, y cómo para añadirles a un modelo.

Preparándose
Esta receta supone que tienes un caso a punto con el mi_módulo addon el módulo
disponible, cuando descrito en Capítulo 3, Creando Odoo Módulos.

Cómo para hacerlo…


El mi_módulo addon el módulo tiene que ala punto tener unos
modelos/library_book.py definiendo un Modelo básico. Lo editaremos para añadir
campos nuevos:
1. Uso la sintaxis mínima para añadir campos al modelo de Libros de la Biblioteca:
De openerp modelos de importación,
clase de campos
LibraryBook(modelos.Modelo):
# ...
Campo_de nombre = cortos.Char( Eshort
Título') nota = campos.Texto('Notas
Internas') campos =
estatales.Selección(
[('Borrador', 'No
Disponible'), ('disponible',
'Disponible'), ('perdido',
'Perdido')],
Estate')
Campos = de
descripción.Html('Descripción') campos =
de cubierta.Binario('Cubierta de Libro')

66
Capítulo 4

Fuera_de_campos = de
impresión.Booleano('Fuera de Impresión?')
Campos_de liberación = de la fecha.Fecha(
esFecha de arrendamiento') la fecha_actualizó
= campos.Datetime('Último Actualizado')
campos = de páginas.Entero('Número de
Páginas') el lector que_valora =
campos.Flotador(
Esader Índice Mediano',
(14, 4), # precisión Opcional (total, decimales),
)

2. Todos estos campos apoyan unos cuantos atributos comunes. Cuando un ejemplo,
podríamos editar las páginas de preceder campo para añadirles:
Campos = de páginas.Entero(
cuerda='Número de Páginas',
default=0,
Ayuda='cuenta de página de libro
Total', agrupa='base.Usuario_de grupo',
declara={'cancelar': [( esadonly',
Cierto)]}, la copia=Cierta,
El índice=Falso,
readonly=Falso,
Requerido=Falso, la
compañía_dependiente=Fal
so,
)

3. El Char los campos apoyan unos cuantos atributos concretos. Cuando un


ejemplo, podemos editar el campo_de nombre corto para añadirles:
Campos_de nombre = corto.Char( Cuerda=
hort Título', medida=100, # Para
Char sólo
Traduce=Falso, # también para campos de Texto
)

4. Los campos de HTML también tienen atributos concretos:


Campos = de descripción.Html(

Cuerda='Descripción',

# Opcional:
sanitize=Cierto,
estilo_de
cinta=Falso,
traduce=Falso,
)

Upgrading El módulo hará estos cambia eficaces en el Odoo modelo.


67
Modelos de aplicación

Cómo trabaja…
Los campos están añadidos a modelos por definir un atributo en su clase de Pitón. El non-el
campo relacional escribe disponible es como sigue:
f Char Para valores de cuerda.
f Texto para multi-valores de cuerda de la línea.
fSelecciónpara listas de selección. Esto tiene una lista de valores y pares de
descripción. Elvalor que está seleccionado es qué consigue almacenado en la
base de datos, y pueda ser una cuerda o un entero.
fHtmlEs similar al campo de Texto, pero está esperado para almacenar texto rico
en el formato de HTML.fLos camposbinarios almacenan archivos binarios, como
imágenes o documentos.
f Tiendas booleanas valores/Falsos Ciertos.
fFechastores valores de fecha. El ORM les maneja en el formato de cuerda, pero
estánalmacenados en la base de datos como fechas. El formato utilizó está definido
en openerp.Campos.
FORMATO_de FECHA.
fDatetimePara fecha-valores de tiempo. Están almacenados en la base de datos
en un naive tiempo de fecha,en tiempo de UTC. El ORM les representa como
cuerda y también en tiempo de UTC. El formato utilizó está definido en
openerp.Campos.DATETIME_FORMATO.
f Campos de entero necesitan no explicación más lejana.
fCamposde flotador almacenan valores numéricos. La precisión opcionalmente
puede ser defined con unnúmero total de dígitos y pares de dígitos decimales.
fMonetariopuede almacenar una cantidad en una moneda segura; es
también explicado enotra receta.
El primer paso en la receta muestra la sintaxis mínima para añadir cada tipo de campo.
Las definiciones de campo pueden ser expandidas para añadir otros atributos
opcionales, cuando mostrados en paso 2.
Aquí es una explicación para los atributos de campo utilizó:

fLa cuerdaes el campo título, utilizado en UI etiquetas de vista. De hecho es


opcional; si no puesto,una etiqueta será derivada del field nombre por añadir
caso de título y reemplazando underscores con espacios.
f La medida sólo aplica a Char campos y es el número máximo de caracteres dejó.
En general, es aconsejó no para utilizarlo.
fTraducircuándo puesto a Cierto, hace el campo translatable; pueda
aguantar un valordiferente que depende de la lengua de interfaz del usuario.
fdefaultEs el default valor. También pueda ser una función que suele calcular
eldefault valor. Por ejemplo, default=_computar_default, dónde _computa_
default es un método demultó en el modelo antes de la definición de campo.
f La ayuda es un texto de explicación mostrado en el UI tooltips.

68
Capítulo 4

fLos gruposhace el campo disponible único a algunos grupos de seguridad. Es


una cuerdaconteniendo una coma-lista separada de XML IDs para grupos de
seguridad. Esto está dirigido con más detalle en Capítulo 10, Seguridad de Acceso.
fLos estadosdeja la interfaz de usuario a dinámicamente puesto el valor
parareadonly,requerido, y atributos invisibles, dependiendo de el valor
del campo estatal.
Por tanto, requiere un campo estatal para existir y ser utilizado en la vista de forma
(incluso si es invisible).
fBanderasde copia si el valor de campo está copiado cuándo el registro está
duplicado. Por default, es Cierto para no-relacional y Muchos2un campos y
Falsos para Uno 2muchos y computó campos.
fÍndice, cuándo puesto a Cierto, marcas para la creación de un índice de
base de datos para el campo,dejando búsquedas más rápidas. Reemplaza el
deprecated selecciona=1 atributo.
fElreadonlyla bandera hace el campo leído-único por default en el usor
interfaz.fLa banderarequerida hace el campo obligatorio por default en la
interfaz de usuario.
fElsanitizela bandera está utilizada por campos de HTML y desnuda su
contenido de potencialmenteinsecure etiquetas.
fEstilo_de cintaes también un atributo de campo del HTML y tiene el
sanitization a también sacarelementos de estilo.
fLa compañía_la banderadependiente hace la tienda de campo valores
diferentes por compañía.Reemplaza el deprecated tipo de campo de la
Propiedad.

Allí ha más…
El campo de Selección también acepta una referencia de función en vez de una lista,
cuando su "atributo" de selección. Esto deja para dinámicamente generó listas de
opciones. Puedes ver un ejemplo de este en el Añadir las relaciones dinámicas que
utilizan receta de campos de la Referencia, donde un atributo de selección es también
utilizó.
La Fecha y Datetime campo objects expone unos cuantos métodos de utilidad que puede
ser conveniente.

Para Fecha, tenemos el siguientes:

fCampos.Fecha.De_cuerda(valor_de cuerda)parses la cuerda a un objeto


de fecha.ffields.date.to_Cuerda(valor_de fecha)representa
elobjetode Fecha como cuerda.ffields.Fecha.Hoy()regresa el día actual
en formato de cuerda.
fCampos.Fecha.Contexto_hoy(récord)regresa el día actual en formato de
cuerdasegún el timezone del registro es (o recordset) contexto.
69
Modelos de aplicación

Para Datetime, tenemos el siguientes:

fCampos.Datetime,de_cuerda(valor_de cuerda)parses la cuerda a


undatetime objeto.
fCampos.Datetime,a_cuerda(datetime_valor)representa
eldatetimeobjeto como cuerda.
fCampos.Datetime,ahora()regresa el día actual y tiempo en formato de cuerda.
Esto esapropiado de utilizar para default valores.
fCampos.Datetime,contexto_timestamp(registro, valor)convierte
unvalornaive fecha-tiempo a un timezone-fecha consciente-cronometra utilizar
el timezone en el contexto de récord . Esto no es adecuadof o default valores.
Otro que campos básicos, también tenemos campos relacionales: Muchos2un,
Uno2muchos, y
Muchos2muchos. Estos están explicados en el Añadir campos relacionales a una receta
de modelo.

Es también posible de tener campos con automáticamente computó valores, defining la


función de computación con el computar atributo de campo. Esto está explicado en el
Añadiendo computó campos a una receta de modelo.
Unos cuantos campos están añadidos por default en Odoo modelos, así que no tendríamos
que utilizar estos nombres para nuestros campos. Estos son el id campo, fo el registro es
identificador generado automáticamente , y unos cuantos campos de registro de la
auditoría, los cuales son como sigue:
fCrea_la fechaes la creación récord
timestampfcrea_uides el usuario que creó el
récordfescribir_la fechaes el último grabado
edita timestampfwrite_uides el usuario que
último editado el registro

La creación automática de estos campos de registro puede ser inutilizada por poner el
_acceso_de registro=atributo de modelo Falso.

Otra columna especial que puede ser añadido a un modelo es activo. Tenga que ser una
bandera Booleana allowing para registros de marca como inactive. Su definición parece
esto:
Campos = activos.Booleano('Activo', default=Cierto)

Por default, registros únicos con conjunto activo a Cierto es visible. Para tenerles
recuperado, necesitamos utilizar un filtro de ámbito con [('activo', '=', False)].
Alternativamente, si el
'Prueba_activa': el valor Falso está añadido al Contexto de entorno, el ORM
no filtrará fuera de inactive registros.
70
Capítulo 4

Utilizando un campo de flotador


con configurable precisión
Cuándo utilizando campos de flotador, podemos want para dejar el usuario de fin
configura la precisión que es para ser utilizado. El módulo de Configuración de Precisión
Decimal addon proporciona esta capacidad.
Añadiremos un campo de Precio del Coste al modelo de Libro de la Biblioteca, con un
usuario-configurable número de dígitos.

Preparándose
Nosotros reutilización el mi_módulo addon módulo de Capítulo 3, Creando Odoo Módulos.

Cómo para hacerlo…


Necesitamos instalar el módulo_de precisión decimal, añadir una "entrada"
de Uso para nuestra configuración, y entonces utiliza él en el campo de modelo:
1. Marca seguro el Decimal Accuracy el módulo está instalado; selecciona
Aplicaciones de la carta superior, sacar el default filtro, buscar la aplicación de
Configuración de Precisión Decimal, e instalarlo si no es ya instalado:

2. Activar el Modo de Desarrollador en el Aproximadamente caja de diálogo,


available dentro del ? Icono en la barra de carta en la parte superior. Esto habilitará
los Encuadres | carta Técnica.
3. Acceso las configuraciones de Precisión Decimales. Para hacer este, abre los
Encuadres carta superior y seleccionar Estructura | de Base de datos Técnica |
Exactitud Decimal. Tendríamos que ver una lista del actualmente definió
encuadres.
71
Modelos de aplicación

4. Añadir una configuración nueva, poniendo Uso para Reservar Precio y escogiendo
el
Precisión de dígitos:

5. Añadir la dependencia nueva al __openerp__.py Manifiesta archivo. Tenga que


ser similar a esto:
{ 'Nombre': 'Capítulo 03 código',
'Depende': ['base', 'precisión_decimal],
'Dato': ['libro/de biblioteca_de las vistas.xml'] }

6. Para añadir el campo de modelo que utiliza este encuadre de precisión


decimal, editar los modelos/ library_book.py archivo por añadir el
siguiente:
De openerp.addons Importa precisión_decimal como dp
# ...
Clase LibraryBook(modelos.Modelo):
# ...
Campos_de precio = del coste.Flotador(
'El libro Cuesta', dp.Consigue_precisión('Precio de
Libro))

Cómo trabaja…
El conseguir_precisión() miradas de función arriba del nombre en el Decimal
Unccuracy campo de Uso y regresa un tuple representando precisión de 16 dígitos con
el número de decimales definió en la configuración.
Utilizando esta función en la definición de campo, en vez de tenerlo hardcoded, deja el
usuario de fin para configurar él según sus necesidades.
72
Capítulo 4

Añadiendo un campo monetario a un Modelo


Odoo Tiene el soporte especial para valores monetarios relacionó a una moneda. Dejado es
ver cómo para utilizar él en un Modelo.

El campo Monetario estuvo introducido en Odoo 9.0 y no es


disponible en versiones anteriores. Si estás utilizando Odoo 8.0,
el tipo de campo del flotador es vuestra alternativa mejor .

Preparándose
Nosotros reutilización el mi_módulo addon módulo de Capítulo 3, Creando Odoo Módulos.

Cómo para hacerlo…


El campo monetario necesita un complementario currency campo para almacenar la moneda para
las cantidades.

El mi_módulo ya tiene unos modelos/library_book.py definiendo un Modelo básico.


Editaremos esto para añadir el necesitó campos:
1. Añadir el campo para almacenar la moneda que es para ser utilizado:
Clase LibraryBook(models.model):
# ...
Moneda_id = campos.Muchos2un( ess.Moneda',

cuerda='Moneda')

2. Añadir el campo monetario para almacenar nuestra cantidad:


Clase LibraryBook(modelos.Modelo):
# ...
Campos_de precio =
minorista.Monetario( esPrecio
de cola',
# Opcional: campo_de moneda='moneda_id',
)

Ahora, upgrade el addon módulo, y los campos nuevos tendrían que ser disponibles en el
Modelo. No serán visibles en vistas hasta que están añadidos a ellos, pero podemos
confirmar su adición por inspeccionar los campos de Modelo en Encuadres | Base de datos |
Técnica Structure | Modelos.
73
Modelos de aplicación

Cómo trabaja…
Los campos monetarios son similares de Flotar campos, pero Odoo es capaz de representarles
correctamente en la interfaz de usuario desde entonces sabe lo que su moneda es a través de
un segundo campo para aquel propósito.

Este campo de moneda está esperado para ser moneda nombrada_id, pero podemos
utilizar cualquier nombre de campo nos gusta mientras está indicado utilizando el campo_de
moneda parámetro opcional.
Te podría gustar saber que la precisión decimal para la cantidad está tomada de la
definición de moneda (el campo_de precisión decimal del res.Modelo de moneda).

Añadiendo campos relacionales a un


Modelo
Relaciones entre Odoo los modelos están representados por campos relacionales.
Podemos tener tres tipos diferentes de relaciones: muchos-a-un, one-a-muchos, y
muchos-a-muchos. Mirando en el ejemplo de Libros de la Biblioteca, vemos que cada
libro puede tener un Editor, así que podemos tener un muchos-a-una relación entre libros
y editores.
Mirando en él del punto de vista de Editores, cada Editor puede tener muchos Libros. Tan,
el anterior muchos-a-una relación implica un un-a-mucha relación inversa.
Finalmente, hay casos donde podemos tener un muchos-a-mucha relación. En nuestro
ejemplo, cada libro puede tener varios (muchos) Autores. E inversely, cada Autor puede
haber written muchos libros. Mirando en él de cualquier lado, esto es un muchos-a-mucha
relación.

Preparándose
Nosotros reutilización el mi_módulo addon módulo de Capítulo 3, Creando Odoo Módulos.

Cómo para hacerlo…


Odoo Utiliza el modelo de Socio, res.Socio, para representar persons,
organizaciones, y direcciones. Tan, tendríamos que utilizar él para autores y editores.
Editaremos los modelos/ library_book.py archivar para añadir estos campos:
1. Añade a la biblioteca Reserva el muchos-a-un campo para el
editor del libro: clase LibraryBook(modelos.Modelo):
# ...
Editor_id = campos.Muchos2un( ess.Socio',
cuerda='Editor',
# Opcional:
ondelete'et null',
contexto={},
ámbito=[],
)

74
Capítulo 4

2. Para añadir el-a-mucho campo para los libros de un editor, necesitamos extender
el modelo de socio. Para simplicity, añadiremos aquello al mismo archivo de Pitón:
Clase
ResPartner(modelos.Modelo):
_hereda = ess.Socio'
libro_ids =
campos.Uno2muchos(
'Biblioteca.Libro',
'editor_id', cuerda='Publicado
Reserva')

3. El muchos-a-mucha relación entre libros y autores era already creó, pero dejado es
revisit lo:
Clase LibraryBook(modelos.Modelo):
# ...
Autor_ids = campos.Muchos2muchos( ess.Socio',

cuerda='Autores')

4. La misma relación, pero de autores a libros, tendría que ser añadido al modelo de
Socio: clase ResPartner(modelos.Modelo):
# ...
Libro_ids = campos.Muchos2muchos(
'Biblioteca.Libro',
cuerda='Authored
Reserva',
# Relación='libro_de biblioteca_res_socio_rel' #
opcional
)

Ahora, upgrade el addon módulo, y los campos nuevos tendrían que ser disponibles en el
Modelo. No serán visibles en vistas until están añadidos a ellos, pero podemos confirmar su
adición por inspeccionar los campos de Modelo en Encuadres | Modelos | de Estructura de
Base de datos | Técnicos.

Cómo trabaja…
Muchos-a-un campos añaden una columna a la mesa de base de datos del modelo que
almacena la base de datos ID of el registro relacionado. En el nivel de base de datos, un
constreñimiento clave extranjero también será creado para él, asegurando que el
almacenado IDs es una referencia válida a un registro en la mesa relacionada. Ningún índice
de base de datos está creado para estos campos de relación, pero esto a menudo tendría
que ser considerado; pueda ser hecho por añadir el índice de atributo=Cierto.
Podemos ver que hay cuatro más atributos podemos utilizar para muchos-a-un campos:
75
Modelos de aplicación

El ondelete el atributo determina qué pasa cuándo el related el registro está eliminado. Por
ejemplo, qué pasa a Libros cuándo su registro de Editor está eliminado? El default es eset
null', poniendo un valor vacío en el campo. También pueda ser esestricto', el cual
impide el registro relacionado de ser eliminado, o 'cascad e', el cual causa el enlazado récord a
también
Ser eliminado.

El último dos (contexto y ámbito ) es también válido para los otros campos relacionales.
Son mayoritariamente significativos en el lado de cliente y en el nivel de modelo actúa tan
default valores para ser utilizados en el client-vistas de lado.
fEl contextoañade variables al contexto de cliente cuándo clicking a través del
campo a laregistro relacionado. Podemos, por ejemplo, lo utiliza para
poner default valores en aquella vista.
fEl ámbitoes un filtro de búsqueda utilizó para limitar la lista de relacionado
records disponible para seleccióncuándo escogiendo un valor para nuestro campo.
Ambos contexto y el ámbito están explicados con más detalle en Capítulo 8, Backend Vistas.

Uno-a-muchos campos son el revés de muchos-a-una relaciones, y a pesar de que están


añadidos a modelos justo como otros campos, tienen no representación real en la base de
datos. Son en cambio programmatic atajos y habilitar vistas para representar estas listas de
relacionó registros.

Muchos-a-muchas relaciones también no añaden columnas en las mesas para los modelos.
Este type de la relación está representada en la base de datos que utiliza una mesa de
relación intermedia, con dos columnas para almacenar el dos relacionó IDs. Añadiendo una
relación nueva entre un Libro y un Autor crea un registro nuevo en la mesa de relación con el
ID para el Libro y tél ID para el Autor.
Odoo Automáticamente maneja la creación de esta mesa de relación. El nombre de mesa de la
relación es, por default, construyó utilizar el nombre del dos relacionó modelos más un _rel
sufijo. Pero, podemos override lo utilizando el atributo de relación. Un caso to mantiene en
la mente es cuándo los dos nombres de mesa es bastante grande para la base de datos
automáticamente generada identificadores para superar el
PostgreSQL Límite de 63 caracteres.

Como regla de pulgar, si los nombres de los dos relacionaron las mesas superan 23
caracteres, tendrías que utilizar el atributo de relación para poner nombre más a escaso.
En la sección próxima, iremos a más detalle en este.

Allí ha más…
El Muchos2un campos apoyan un coche adicional_une atributo. Es una bandera que
deja el ORM para utilizar SQL une en este campo. Because De este, él bypasses el habitual
ORM control como control de acceso del usuario y reglas de acceso récord. En un caso
concreto, pueda solucionar un asunto de rendimiento, pero está aconsejado para evitar
utilizándolo.
76
Capítulo 4

Hemos visto la manera más corta a define los campos relacionales. Para completeness,
estos son los atributos concretos a este tipo de campo:
El2muchos atributos de campo son como sigue:

fcomodel_Nombre: Esto es el identificador de modelo del objetivo y es obligatorio


para todos los camposrelacionales, pero pueda ser posición definida -sensato sin
la palabra clave
finverse_Nombre: Esto aplica sólo a Un2muchosy es el nombre de campo en
el modelode objetivo para el inverse Mucha2una relación
fLímite: Esto aplica a Un2muchosy Muchos2muchosy pone un límite
opcional ennúmero de registros de leer aquello está utilizado en el nivel de
interfaz del usuario
El Muchos2muchos atributos de campo son como sigue:

f comodel_Nombre: (cuando definido más temprano)


fRelación: Esto es el nombre para utilizar para la mesa que apoya la relación,
primordialel automatically definió nombre
fColumna1: Esto es el nombre paraMucho2uncampo en la mesa
relacional que enlaza a este modelo
fColumna2: Esto es el nombre paraMucho2uncampo en la mesa
relacional que enlaza a el comodel
Para Muchos2muchas relaciones, en la mayoría de casos el ORM tomará cuidado
perfecto del default valores para estos atributos. Es incluso capaz de detectar inverse
Muchos2muchas relaciones, detectando el ya existiendo mesa de relación y
apropiadamente inverting la columna1 y columna2 valores.
Pero allíun re dos casos donde necesitamos dar un paso en y proporcionar nuestros
valores propios para estos atributos. Uno es el caso donde necesitamos más de uno
Muchos2mucha relación entre los mismos dos modelos. Para este para ser posible, prpers
tenemos que proporcionar con una mesa de relación nombra aquello es diferente de la
primera relación. El otro caso es cuándo los nombres de base de datos del relacionó las
mesas son mucho tiempo bastante para la relación automáticamente generada nombre
para superar el 63 carácter PostgreSQL límite para nombres de objeto de la base de datos.

La relación tcapaz el nombre automático es modelo <1>_<modelo2>_rel. Pero esta


mesa de relación también crea un índice para su llave primaria con el identificador
siguiente:
<Modelo1>_<modelo2>_rel_<modelo1>_id_<modelo2>_id_llave

También necesita conocer el 63 límite de caracteres. Tan, si elt wo nombres de mesa


combinaron superar un total de 63 caracteres, probablemente tendrás el problema que
conoce los límites y necesitará a manualmente puesto el atributo de relación.
77
Modelos de aplicación

Añadiendo una jerarquía a un Modelo


Las jerarquías son represented utilizando relaciones de modelo con él; cada registro tiene un
registro de padre en el mismo modelo y también tiene muchos registros de niño. Esto puede
ser conseguido por sencillamente utilizando muchos-a-una relaciones entre el modelo y él.
Pero Odoo también proporciona soporte mejorado para este tipo del campo que utiliza el
Nested modelo de conjunto
(https://en.wikipedia.org/wiki/nested_set_model). Cuándo activado, las
consultas que utilizan el niño_del operador en sus filtros de ámbito correrá
significativoly más rápido.
Quedándose con el ejemplo de Libros de la Biblioteca, construiremos un árbol de categoría
jerárquico que podría soler categorize libros.

Preparándose
Nosotros reutilización el mi_módulo addon módulo de Capítulo 3, Creando Odoo Módulos.

Cómo para hacerlo…


Añadiremos un archivo de Pitón nuevo, modelos/library_book_categ.py, para el
árbol de categoría, mostrado como sigue:
1. Para tener el archivo de código de Pitón nuevo cargado, añadir esta línea a
modelos/__init__.py : De . Libro de biblioteca_de la
importación_categ

2. Para crear el modelo de Categoría del Libro con el parent y relaciones de niño,
crear los modelos/library_book_categ.py archivo con el siguiente:
# -*- Codificación: utf-8 -*-
De openerp modelos de importación,
campos, api clase
BookCategory(modelos.Modelo):
_Nombre =
'biblioteca.Libro.Categoría'
campos = de
nombre.Char('Categoría')
parent_id = campos.Muchos2un(
'Biblioteca.Libro.Categorí
a', cuerda='Categoría de
Padre', ondelete=
esestricto', el
índice=Cierto)
Niño_ids = campos.Uno2muchos(
'biblioteca.Libro.Categoría', 'padre_id',
cuerda='Categorías de Niño')

78
Capítulo 4

3. Para habilitar el especial holaerarchy soporte, también añadir el siguiente:


_Tienda_de padre = Cierta
El padre_dejó = campos.Entero(el
índice=Cierto) padre_campos =
correctos.Entero(el índice=Cierto)

4. Para añadir un control que impide looping relaciones, añadir la línea siguiente al
modelo:
@api.Apremia('padre_id') def
_jerarquía_de control(self):
Si no self._Recursión_de
control(): levanta
modelos.ValidationError(
'Error! No puedes crear categorías recursivas.')

Finalmente, un módulo upgrade tendría que hacer estos cambia eficaces.

Cómo trabaja…
Pasos 1 y 2 crea el nuevo model con hierarchic relaciones. El Mucha2una relación añade un
campo a referencia el registro de padre. Para niño más rápido descubrimiento récord, este
campo es indexed en la base de datos que utiliza el índice=parámetro Cierto. El
padre_id el campo tiene que haber ondelete puesto a cualquiera 'cascade' o
esestricto'.

Al llegar a este punto, tenemos todo aquello está requerido para tener un hierarchic
estructura. Pero hay unos cuantos más adiciones podemos hacer para realzarlo.
El2mucha relación no añade cualesquier campos adicionales a la base de datos pero
proporciona un sh ortcut para acceder todos los registros con este registro como su
padre.
En paso 3, activamos el soporte especial para jerarquías. Esto es útil para alto-leído pero
abajo-escribir instrucciones, desde entonces trae el dato más rápido que explora a expensas
de más costoso escribe operations. Está hecho por añadir dos helper campos, el
padre_dejado y derecho_de padre , y poniendo el atributo de modelo a _tienda_de
padre=Cierta . Cuándo este atributo está habilitado, el dos helper los campos soler dato de
tienda en búsquedas en el hierarchic árbol.
Por default, está supuesto que el campo para que así conste el padre se apellida
padre_id, pero un nombre diferente puede ser utilizado. En aquel caso, el nombre de
campo correcto tendría que ser indicado utilizando el padre de atributo de _modelo
adicional_nombre. El default es como sigue:

_parent_Nombre = 'padre_id'

Paso 4 está aconsejado para impedir cyclic dependencias en la jerarquía— que es, habiendo
un récord ambos en el ascendentes y descendiendo árboles. Esto es peligroso para
programas que navigate a través del árbol, desde entonces pueden conseguirint o un bucle
infinito. Los modelos.El modelo proporciona un método de utilidad para este
(_recursión_de control) que hemos reused aquí.

79
Modelos de aplicación

Allí ha más…
La técnica mostrada aquí tendría que ser utilizado para "jerarquías" estáticas, los cuales están
leídos y queried a menudo pero raramente actualizó. Categorías de libro son un ejemplo bueno ,
desde la Biblioteca no
Continuamente estar creando categorías nuevas, pero los lectores a menudo serán
restringiendo sus búsquedas a una categoría y todas sus categorías de niños. La razón
parath es mentiras en la implementación del Nested Pone Modelo en la base de datos, el
cual requiere una actualización del padre_dejado y padre_columnas correctas (y los
índices de base de datos relacionados) para todos los registros siempre que una categoría
está insertada, sacado, o movió. Esto puede ser una operación muy cara , especialmente
cuándo las ediciones múltiples están siendo actuadas en paralelo transacciones.

Si estás tratando una estructura jerárquica muy dinámica, el padre estándar_id y


niño_ids las relaciones pueden resultar en rendimiento mejor.

Anuncioding validaciones de
constreñimiento a un Modelo
Los modelos pueden tener las validaciones que les impiden de introducir undesired
condiciones. Dos tipos diferentes de constreñimiento pueden ser utilizados: los
comprobados en el nivel de base de datos y los comprobados en el nivel de servidor.
Database Constreñimientos de nivel están limitados a los constreñimientos apoyados por
PostgreSQL. El más generalmente utilizado es la UNIQUE constreñimientos, pero CONTROL
y EXCLUIR los constreñimientos también pueden ser utilizados. Si estos no son bastante
para nuestras necesidades, podemos utilizar Odoo nivel de servidor apremiats, escrito en
código de Pitón.
Utilizaremos el modelo de Libro de la Biblioteca creado en Capítulo 3, Creando Odoo Módulos,
y añadir un par de constreñimientos a él. Añadiremos un constreñimiento de base de datos
que impide títulos de libro duplicado, y un constreñimiento de modelo de la Pitón que impide
fechas de liberación en el futuro.

Preparándose
Nosotros reutilización el mi_módulo addon módulo de Capítulo 3, Creando Odoo Módulos.

Lo esperamos para contener al menos el siguiente:

# -*- Codificación: utf-8 -*-


De openerp modelos de importación,
clase de campos
LibraryBook(models.Modelo):
_Nombre = 'biblioteca.Libro'
Campos = de nombre.Char('Título',
requerido=Cierto) campos_de liberación = de
la fecha.Fecha( esFecha de arrendamiento')

80
Capítulo 4

Cómo para hacerlo…


Editaremos el LibraryBook clase en los modelos/library_book_categ.py archivo
de Pitón:

1. Para crear el constreñimiento de base de datos, añadir un atributo de modelo:


Clase LibraryBook(modelos.Modelo):
# ...
_sql_Constreñimiento
s = [
('nombre_uniq',
'UNIQUE (nombre)',
'Título de libro tiene que ser único.')
]

2. Para crear el constreñimiento de código de la Pitón, añadir


un método de modelo: de openerp importación api
Clase LibraryBook(modelos.Modelo):
# ...
@api.Apremia('liberación_de
fecha') def _fecha_de
liberación_del control(self):
Para r en self:
Si r.Campos_de liberación > de la
fecha.Fecha.Hoy(): levanta
modelos.ValidationError(
Esfecha de arrendamiento tiene que ser
antiguamente')

Después de que these los cambios están hechos al archivo de código, un addon módulo
upgrade y el servidor retoma está necesitado.

Cómo trabaja…
El primer paso tiene un constreñimiento de base de datos creado en la mesa del modelo. Está
aplicado en el nivel de base de datos. El _sql_modelo de constreñimientos atribuye unccepts
una lista de constreñimientos para crear. Cada constreñimiento está definido por un tres
elemento tuple; están listados como sigue:

fUn sufijo para utilizar para el identificador de constreñimiento. En nuestro ejemplo,


utilizamosnombre_uniqy el nombre de constreñimiento resultante es
nombre_de libro_de la biblioteca_uniq.
f El SQL para utilizar en el PostgreSQL instrucción para alterar o crear la mesa de
f base de datos. Un mensaje para informar al usuario cuándo el constreñimiento
está violado.
Cuando mencionado más temprano, otros constreñimientos de mesa de la base de datos
pueden ser utilizados. Nota que column constreñimientos, como NO NULL, no puede ser
añadido de este modo. Para más información en PostgreSQL constreñimientos en general
y constreñimientos de mesa en particular, tomar una mirada
En http://www.postgresql.org/docs/9.4/static/ddl-
constraints.html.

81
Modelos de aplicación

En el segundo paso, añadimos un método para actuar una validación de código de la


Pitón. Está decorado con @api.Apremia , significado que lo tendría que ser ejecutado para
correr controles wgallina uno de los campos en la lista de argumento está cambiado. Si el
control falla, un ValidationError la excepción tendría que ser levantada.

El _atributo de modelo de los constreñimientos es todavía


disponible pero ha sido deprecated desde entonces versión 8.0. En
cambio, tendríamos que utilizar métodos con the nuevos
@api.Apremia decorator.

Añadiendo computó campos a un Modelo


A veces, necesitamos tener un campo que tiene un valor calculado o derivado de otros
campos en el mismo récord o en relacionó registros. Un ejemplo típico es la cantidad total
que es calculated por multiplicar un precio de unidad con una cantidad. En Odoo
modelos, esto puede ser conseguido utilizando computó campos.
Para mostrar cómo computó trabajo de campos, añadiremos uno al modelo de Libros de
la Biblioteca para calcular los días desde la fecha de liberación del libro.
Es también possible a la marca computó los campos editables. También implementaremos esto
en nuestro ejemplo.

Preparándose
Nosotros reutilización el mi_módulo addon módulo de Capítulo 3, Creando Odoo Módulos.

Cómo para hacerlo…


Editaremos los modelos/library_book.py archivo de código para añadir un campo
nuevo y los métodos que apoyan su lógica:
1. Inicio por añadir el campo nuevo al modelo de Libros de
la Biblioteca: clase LibraryBook(modelos.Modelo):
# ...
Campos_de días = de la edad.Flotador(
cuerda='los días Desde entonces
Liberan',
computa='_computar_edad',
inverse='_inverse_edad',
búsqueda='_edad_de búsqueda',
La tienda=Falsa,
computa_sudo=Falso,
)
82
Capítulo 4

2. Luego, añadir el método con la lógica de computación del valor:


# ...
De openerp importación api # si no ya importó
De openerp.Fecha de importación de los campos como fDate
# ...
Clase LibraryBook(modelos.Modelo):
# …
@api.Depende('liberación_de
fecha') def
_computar_edad(self):
Hoy = fDate.De_cuerda(fDate.Hoy()) para
libro en self.Filtrado('liberación_de
fecha'):
Delta = (fDate.De_cuerda(libro.Liberación_de
fecha - hoy)
Libro.Delta_de días = de la edad.Días

3. Para añadir el método que implementa la lógica para escribir en el campo


computado, uso el código siguiente:
De datetime importación timedelta como td
# ...
Clase LibraryBook(modelos.Modelo):
# …
def _inverse_Edad(self): hoy =
fDate.De_cuerda(fDate.Hoy())
Para libro ense lf.Filtrado('liberación_de
fecha'): d = td(libro=de días.Días_de
edad) - hoy libro.Liberación_de fecha =
fdate.to_cuerda(d)

4. Para implementar la lógica que te deja para buscar en el campo computado,


uso el código siguiente:
# De datetime importación timedelta
como td clase
LibraryBook(models.Modelo):
# …
def _Edad_de búsqueda(self, operador, valor):
hoy = fDate.De_cuerda(fDate.Hoy()) días_de
valor = td(valor=de días)
Fecha_de valor = fdate.to_cuerda(hoy - días_de
valor) regreso [('liberación_de fecha', operador,
fecha_de valor)]

Un Odoo retomar seguido por un módulo upgrade tendría que ser necesitado a
correctamente activar estas adiciones nuevas.
83
Modelos de aplicación

Cómo trabaja…
La definición de un campo computado es el mismo tan el para un campo regular, exceptúa
que un computar el atributo está añadido a specify el nombre del método para utilizar para
su computación.
La semejanza puede ser engañosa, desde entonces computó los campos son
internamente bastante diferentes de campos regulares. Computó los campos son
dinámicamente calculados en runtime, y a no ser que específicamente añades that te
apoyar, no son writeable o searchable.
La función de computación es dinámicamente calculada en runtime, pero el ORM usos
caching para evitar inefficiently recalculating él cada vez su valor está accedido. Tan,
necesita saber lo que otro fields depende de, utilizando el @depende decorator para
detectar cuándo su cached los valores tendrían que ser invalidados y recalculated.

Marca seguro que el computar la función siempre pone un valor en


el campo computado. Otherwise, un error será levantado. Esto puede
pasar wgallina tienes si condiciones en vuestro código que a veces
fallar para poner un valor en el campo computado, y puede ser
delicado de depurar.

Escribe el soporte puede ser añadido por implementar el inverse función; utiliza el valor
asignó al campo computado para actualizar elo rigin campos. Naturalmente, este sentido de
marcas único para cálculos más sencillos; no obstante, hay casos quietos donde lo puede
ser útil. En nuestro ejemplo, lo hacemos posible para poner la fecha de liberación del libro
por editar los Días Desde entonces Liberan campo computado.

Esun lso posible de hacer searchable un no-almacenó campo computado por poner el
atributo de búsqueda al nombre de método para utilizar (similar de computar e
inverse).
Aun así, este método no es esperado para implementar la búsqueda real. En cambio, recibe tan
parámetros el operador y valorar utilizado para buscar en el campo y está esperado para regresar
un ámbito con las condiciones de búsqueda de la sustitución para utilizar. En nuestro ejemplo,
traducimos una búsqueda de los Días Desde entonces campo de Liberación a una condición de
búsqueda equivalente en la Liberación Dcomió campo.

La tienda opcional=la bandera Cierta hace el campo almacenado en la base de datos.


En este caso, después de ser computado, los valores de campo están almacenados en la
base de datos, y de allí encima, están recuperados como campos regulares en vez de ser
recomputed en runtime. Gracias al @api. Depende decorator, el ORM sabrá cuándo estos
almacenaron necesidad de valores para ser recomputed y actualizó. Puedes pensar de él
como persistente cache. También tiene la ventaja de hacer el campo utilizable para
condiciones de búsqueda, ordenando y grouping por operaciones, sin la necesidad de
implementar el método de búsqueda.
El computar_sudo=la bandera Cierta es para ser utilizado en aquellos casos donde la
necesidad de computaciones para ser hecho con elevó privilegios. Esto puede ser el caso
cuándo las necesidades de computación para utilizar dato que no puede ser accesible hasta
el final usuario.

84
Capítulo 4

Exponiendo Relacionó los campos


almacenaron en otros modelos
Cuándo leyendo dato del servidor, Odoo los clientes sólo pueden conseguir valores para los
campos disponibles en el ser de modelo queried. Cliente-código de lado puede't notación de
punto del uso para acceder dato en el relacionó a mesas les gusta el servidor-lata de código
del lado.
Pero aquellos campos pueden ser hechos disponibles allí por añadirles cuando relacionó
campos. Haremos este para hacer la ciudad del editor disponible en el modelo de Libro de
la Biblioteca.

Preparándose.
Nosotros reutilización el mi_módulo addon módulo de Capítulo 3, Crea Odoo Módulos.

Cómo para hacerlo…


Editar los modelos/library_book.py archivar para añadir el campo "relacionado" nuevo:

1. Marca seguro que tenemos un campo para el Editor de libro:


Clase LibraryBook(modelos.Modelo):
# ...
Editor_id = campos.Muchos2un( ess.Socio',

cuerda='Editor')

2. Ahora, añadir el campo relacionado para la ciudad del Editor:


# Clase LibraryBook(modelos.Modelo):
# ...
Campos_de ciudad = del editor.Char(
'Ciudad de editor',
relacionado='editor_id.Ciudad')

Finalmente, necesitamos a upgrade el addon módulo para los campos nuevos para ser
disponibles en el Modelo.

Cómo trabaja…
Relacionó los campos son justo como campos regulares, pero tienen el atributo adicional,
relacionado, con una cuerda para la cadena separada de campos to traverse.
En nuestro caso, accedemos el Editor relacionó récord a través de editor_id , y entonces
leído su campo de ciudad. También podemos tener cadenas más largas, como
editor_id.País_
id.Código_de país.
85
Modelos de aplicación

Allí ha más…
Relacionad los campos son de hecho computó campos. Justo proporcionan una sintaxis
de atajo conveniente para leer valores de campo de relacionó modelos. Como campo
computado, esto significa que el atributo de tienda es también disponible a ellos. Como
atajo, también tienen todo el attributes del referenced campo, como nombre,
translatable, requerido, y tan encima.

Además, apoyan un relacionados_sudo bandera similar de computar_sudo ; cuándo


puesto a Cierto , la cadena de campo es traversed sin comprobar derechos de acceso del
usuario.

Añadiendo dinámico relations utilizando


campos de Referencia
Con campos relacionales, necesitamos decidir por adelantado el modelo de objetivo de la
relación (o comodel).
Pero a veces, podemos necesitar dejar aquella decisión al usuario y primero escoger el
modelo queremos y entonces el registro queremos enlazar a.
Con Odoo, esto puede ser conseguido utilizando campos de Referencia.

Preparándose
Nosotros reutilización el mi_módulo addon módulo de Capítulo 3, Creando Odoo Módulos.

Cómo para hacerlo…


Editar los modelos/library_book.py archivar para añadir el campo relacionado nuevo:

1. Primero añadimos un helper método a dinámicamente construir la lista de modelos


de objetivo seleccionable:
De openerp modelos de importación,
campos, api clase
LibraryBook(modelos.Modelo):
# …
@api.Modelo
def _referencable_Modelos(self):
Modelos = self.env[
Ess.Petición.Enlace'].Búsqueda([]) revuelta
[(x.Objeto, x.name) para x en modelos]

2. Entonces, añadimos el campo de Referencia y utilizar la función anterior para


proporcionar la lista de modelos seleccionables:
ref_doc_id = Campos.Referencia(

selección='_referencable_modelos', la cuerda=

esference Documento')

86
Capítulo 4

Desde entonces estamos cambiando la estructura del modelo, un módulo upgrade


está necesitado para activar estos cambios.

Cómo trabaja…
Campos de referencia son similares a muchos-a-un campos, exceptúa que dejan el usuario
para seleccionar el modelo para enlazar a.
El target el modelo es seleccionable de una lista proporcionada por el atributo de
selección. El atributo de selección tiene que ser una lista de dos elemento tuples,
donde el primero es el modelo identificador interno, y el segundo es una descripción
de texto para él.
Aquí es un ejemplo:

[( Ess.Usuarios', 'Usuario'), ( ess.Socio', 'Socio')]

Aun así, más que proporcionar una lista fija, podemos utilizar una lista de modelo
configurable por usuarios de fin. Aquello es el propósito del construido-en Referenceable
los modelos disponibles en los Encuadres
| Base de datos | técnica Structure opción de carta. El identificador interno de este
modelo es res. Petición.Enlace.
Nuestra receta empezada con proporcionar una función para explorar todo el Modelo
graba que puede ser referenced a dinámicamente construir una lista para ser
proporcionada al atributo de selección. A pesar de que both las formas están dejadas,
declaramos el interior de nombre de la función cita, en vez de una referencia directa a la
función sin cita. Esto es más flexible, y por ejemplo, deja para el referenced función para
ser definida sólo más tarde en el código, el cual es something aquello no es posible
cuándo utilizando una referencia directa.

La función necesita el @api.Modelo decorator porque opera en el nivel de modelo, no


en el recordset nivel.

Mientras esta característica mira buena, viene con una ejecución


significativa elevada. Displaying Los campos de referencia para un número
grande de registros, para caso, en una vista de lista, puede crear cargas de
base de datos pesada como cada valor tiene que ser miradas arriba en una
consulta separada. Es también incapaz de aprovechar base de datos
integridad referencial como lata de campos de relación regular.

Añadiendo características a un Modelo que


utiliza herencia
Uno del más importante Odoo las características es la capacidad de módulo addons
extendiendo las características definieron en otro módulo addons sin teniendo que editar
el código de la característica original. Este might ser para añadir campos o métodos, o
modificar existiendo campos, o extender existiendo métodos para actuar lógica adicional.

87
Modelos de aplicación

Es el más método utilizado frecuentemente de herencia y está referido a por la


documentación oficial como herencia tradicional o herencia clásica.
Extenderemos el construidos en modelo de Socio para añadirlo a un campo computado con
el authored cuenta de libro. Esto implica añadir un campo y un método a un modelo de
existir.

Preparándose
Nosotros reutilización el mi_module addon módulo de Capítulo 3, Creando Odoo Módulos.

Cómo para hacerlo…


Seremos extender el construidos-en modelo de Socio. Tendríamos que hacer este en su
archivo de código de Pitón propio, pero para mantener la explicación como sencillo podemos,
nosotros reutilización el libro/de biblioteca_de los modelos.py Archivo de código:

1. Primero, hacemos seguro el authored_libro_ids inverse la relación es en


el modelo de Socio y añadir el campo computado:
Clase ResPartner(modelos.Modelo):
_Hereda = ess.Socio'
_orden = 'nombre'
authored_Libro_ids = campos.Muchos2muchos(
'biblioteca.Libro', string='Authored Reserva')
Campos_de libros = de la
cuenta.Entero( 'Número de
Authored Libros',
computa='_computar_la
cuenta_reserva'
)

2. Luego, añadir el método necesitó computar la cuenta de libro:


# ...
De openerp importación api # si no ya importó
# Clase ResPartner(models.model):
# ...
@api.Depende('authored_libro_ids')
def _computar_libros_de
cuenta(self):
Para r en self:
r.Libros_de cuenta = len(r.authored_Libro_ids)

Finalmente, necesitamos a upgrade el addon módulo para las modificaciones para tomar
efecto.

Cómo trabaja…
Cuándo una clase de modelo is definió con el _heredar atributo, añade
modificaciones al modelo heredado más que reemplazarlo.

88
Capítulo 4

Esto significa que los campos definieron en la clase de heredar está añadida o
cambiado en el modelo de padre. En la capa de base de datos, está añadiendo campos
en la misma mesa de base de datos.
Los campos son también incrementally modificó. Esto significa que si el campo ya existe en
el super clase, sólo los atributos declararon en la clase heredada está modificada; el otro
unos están mantenidos tan en el parent clase.
Los métodos definieron en la clase de heredar reemplaza el método en la clase de padre. Tan,
a no ser que incluyen una llamada a la versión del padre del método, perderemos
características. Debido a este, cuándo queremos añadir lógica a existir métodos, ellos should
incluir una declaración con super para llamar su versión en la clase de padre. Esto está
hablado con más detalle en Capítulo 5,
Lado de Servidor básico Registro Empresarial.

Allí ha más…
Con el _heredar herencia tradicional, es también posible de copiar el padre model
características a un modelo completamente nuevo. Esto está hecho por sencillamente
añadiendo un _atributo de modelo del nombre con un identificador diferente. Aquí
es un ejemplo:
Clase
LibraryMember(modelos.Modelo):
_hereda = ess.Socio'
_Nombre = 'biblioteca.Miembro'

El modelo nuevo tiene su mesa de base de datos propia con su dato propio totalmente
independiente del res.Modelo de padre del socio. Desde entonces todavía hereda
del modelo de Socio, cualesquier modificaciones más tardías a él también afectará el
modelo nuevo.
En la documentación oficial, esto se apellida prototype herencia, pero en práctica, es
raramente utilizó. La razón es que herencia de delegación normalmente contesta a aquella
necesidad en una manera más eficaz, sin la necesidad a estructuras de dato duplicado. Para
más información encima lo, puedes referir al Uso Delegatherencia de ión para copiar
características a otra receta de Modelo.

Utilizando Modelos Abstractos para


características de Modelo reutilizable
A veces, hay una característica particular que queremos ser capaces de añadir a varios
modelos diferentes. Repitiendo el mismo código en archivos diferentes is práctica de
programación mala, así que sea bueno de ser capaz de implementarlo una vez y ser
capaz a reutilización él muchas veces.
Los modelos abstractos nos dejan a justo crear un modelo genérico que implementa alguna
característica que entonces puede ser heredado por modelos regulares para hacer aquella
característica disponible en ellos.

89
Modelos de aplicación

Cuando un ejemplo, implementaremos una característica de Archivo sencilla. Añade


el campo activo al modelo (si no existe ya) y hace disponible un método de archivo a
toggle the bandera activa. Estos trabajos porque activos es un campo mágico; si
presente en un modelo por default, los registros con activos=Falsos será filtrado fuera
de consultas.
Entonces lo añadiremos al modelo de Libro de la Biblioteca.

Preparándose
Nosotros reutilización el mi_módulo addon módulo de Capítulo 3, Creando Odoo Módulos.

Cómo para hacerlo…


La característica de archivo ciertamente merecería su propio addon módulo, o al menos su
archivo de código de Pitón propio. Pero para mantener la explicación como sencillo como posible,
nosotros cram él a los modelos/
library_book.py Archivo:

1. Añadir el modelo abstracto para la característica de archivo. Tenga que ser


definido en el modelo de Libro de la Biblioteca, donde lo será utilizado:
Clase BaseArchive(modelos.AbstractModel):
_Nombre = 'base.Archivo'
Campos = activos.Booleano(default=Cierto)

def
Hacer_archivo(self)
: para récord en
self:
Récord.Activo = no récord.Activo

2. Ahora, editaremos el modelo de Libro de la Biblioteca para heredar el modelo de


Archivo:
Clase LibraryBook(modelos.Modelo):
_nombre = 'biblioteca.Libro'
_Hereda = ['base.Archivo']
# ...

Un upgrade al addon el módulo está necesitado para los cambios para ser activados.

Cómo trabaja…
Un modelo Abstracto está creado por una clase basada en modelos.AbstractModel En vez
de los modelos habituales.Modelo. Tiene todos los atributos y capacidades de modelos
regulares; la diferencia es que el O Mno creará una representación real para él en la base de
datos. Tan,
No pueda tener ningún dato almacenado en él. Sirve sólo como plantilla para una
característica reutilizable que es para ser añadido a modelos regulares.

90
Capítulo 4

Nuestro Archivo el modelo abstracto es quite sencillo; justo añade el campo activo y un
método a toggle el valor de la bandera activa, el cual esperamos a más tarde ser
utilizados vía un botón en la interfaz de usuario.
Cuándo una clase de modelo está definida con el _heredar atributo, hereda el atributo
methods de aquellas clases, y qué está definido en nuestra clase añade las modificaciones
a estas heredaron características.
El mecanismo en jugar aquí es el mismo tan aquello para una extensión de modelo regular
(cuando por el Añadir características a un Modelo que utiliza receta de herencia). Puedes
haber notado que aquí, _hereda utiliza una lista de identificadores de modelo en vez de una
cuerda con un identificador de modelo. De hecho, _hereda puede tener ambas formas.
Utilizando la forma de lista nos dejo para heredar de múltiple (normalmente Abstracto)
clases. En este caso, somos inheriting justo uno, así que una cuerda de texto sería bien. Una
lista estuvo utilizada en cambio para subrayar que una lista puede ser utilizada.

Allí ha más…
Un digno de mención construido-en el modelo abstracto es ir.needaction_mixin.
Deja para registros de señalar que una acción de usuario está necesitada encima les y
es ampliamente utilizado junto con la Red Social messaging características.
Otro ampliamente el modelo abstracto utilizado es correo .Hilo, proporcionado por el
correo (Habla) addon módulo. Habilita, en modelos, el mensaje presenta que poder la
pared de mensaje vista enel bo ttom de muchas formas.
Otro que AbstractModel, un tercer tipo de modelo es disponible:
modelos.TransientModel.

Tiene representación de base de datos como modelos.Modelo, pero los registros


crearon allí está supuesto para ser provisional y regularmente purged por un servidor-
trabajo planificado. Otro que que, los modelos Transitorios trabajan justo como modelos
regulares.
Son útiles para usuario más complejo las interacciones sabidas como brujos, por ejemplo, para
pedir el usuario alguna entrada a entonces corrido un proceso o un informe. En Capítulo 6, Lado
de Servidor Adelantado Development Técnicas, exploramos cómo para utilizarles para
interacción de usuario adelantado.

Utilizando herencia de Delegación


para copiar características a otro
Modelo
La herencia tradicional que utiliza _hereda actúa en-modificación de sitio para
extender las características del modelo.
Peroel re es casos donde más que modificar un modelo de existir, queremos crear un modelo
nuevo basado en un existiendo un a apalancamiento las características ya tiene. Esto es uno con
Odoo herencia de delegación que usos el atributo de modelo, _hereda (nota el anuncioditional
s).

91
Modelos de aplicación

La herencia tradicional es bastante diferente que el concepto en objeto-programación


orientada. Herencia de delegación en vuelta es similar en aquel un modelo nuevo puede
ser creado para incluir las características de un modelo de padre. También apoya herencia
polimórfica, donde heredamos de dos o más otros modelos.
Tenemos una biblioteca con libros. Es aproximadamente tiempo para nuestra biblioteca a
también tener miembros. Para un miembro de biblioteca, necesitamos toda la identificación
y dato de dirección found en el modelo de Socio, y también lo queremos para mantener
alguna información con respecto a la afiliación: una fecha de inicio, fecha de terminación, y
número de tarjeta.
Añadiendo aquellos campos al modelo de Socio no es la solución mejor desde entonces
serán no ser utilizados para Socios tel sombrero no es miembros. Sea grande de extender el
modelo de Socio a un modelo nuevo con algunos campos adicionales.

Preparándose
Nosotros reutilización el mi_módulo addon módulo de Capítulo 3, Creando Odoo Módulos.

Cómo para hacerlo…


El modelo de Miembro de Biblioteca nuevo should ser en su archivo de código de Pitón
propio, pero para mantener la explicación como sencillo como posible, nosotros
reutilización los modelos/library_book.py archivo:

1. Añadir el modelo nuevo, heredando de res.Socio :


# De openerp modelos de importación, campos # si no
hechos aún así clase LibraryMember(modelos.Modelo):
_Nombre = 'biblioteca.Miembro'
_Hereda = { ess.Socio': 'socio_id'} socio_id
= campos.Muchos2un(
Ess.Socio',
ondelete='cascade')

2. Luego, añadimos los campos que es concreto a Miembros de Biblioteca:


# Clase LibraryMember(modelos.Modelo):
# ...
Campos_de inicio = de la fecha.Fecha(
soyrescoldo Desde entonces') campos_de
fin = de la fecha.Fecha('Fecha de
Terminación') campos_de número = del
miembro.Char()

Ahora, tenemos que upgrade el addon módulo para tener los cambios activaron.
92
Capítulo 4

Cómo trabaja…
El _hereda el modelo entributo pone los modelos de padre que queremos heredar de. En
este caso, justo uno: res.Socio. Su valor es un diccionario de valor clave donde las
llaves son el heredó modelos, y los valores son los nombres de campo utilizó para enlazar
a ellos. Estos son Muchos 2un campos que también tenemos que definir en el modelo. En
nuestro ejemplo, socio_id es el campo que soler enlace con el modelo de padre del
Socio.
A mejor entender cómo trabaja, dejado mirada en qué pasa en el nivel de base de datos
cuándo creamos un Miembro nuevo:
f Un registro nuevo está creado en el res_mesa de socio
f Un registro nuevo está creado en la mesa_de miembro de la biblioteca
fElsocio_idel campo de lamesa_de miembrode la biblioteca está
puesto aliddelres_el socio graba aquello está creado para él
El registro de Miembro es automatically enlazó a un registro de Socio nuevo. Es justo un
muchos-a-una relación, pero el mecanismo de delegación añade alguna magia de modo que
los campos del Socio están vistos como si perteneciendo al registro de Miembro, y un registro
de Socio nuevo es también automáticamente creado con eln ew Miembro.
Te podría gustar saber que esto Socio creado automáticamente el registro ha nada de
particular aproximadamente lo. Es un Socio regular , y si exploras el modelo de Socio,
serás capaz de encontrar aquel registro (sin el dato de Miembro adicional, naturalmente).
Todos los Miembros son al mismo tiempo Socios, pero sólo algunos Socios son también
Miembros.
Tan, qué pasa si eliminas un Socio graba aquello es también un Miembro? Decides por
escoger el ondelete valor para el campo de relación. Para socio_id, utilizamos
cascade. Esto significa que eliminando el Socio también eliminaría el Miembro
correspondiente. Podríamos haber utilizado el encuadre más conservador restringe para
prohibir eliminando el Socio mientras tiene un Miembro enlazado. En este caso, sólo
eliminando el Miembro trabajaría.
Es importante de notar aquella herencia de delegación trabajos únicos para campos y no
para métodos.
Tan, si el modelo de Socio tiene un _algo() método, el modelo de Miembros no
automáticamente lo hereda.

Allí ha más…
Un caso digno de mención de delegación heredaance es el modelo de Usuarios,
res.Usuarios. Hereda de Socios (res.Socio). Esto significa que algunos de los campos
que te puede ver en el Usuario es de hecho almacenado en el modelo de Socio
(notablemente el campo de nombre). Cuándo un Usuario nuevo está creado, también
conseguimos un nuevos automatically creó Socio.
También tendríamos que mencionar que herencia tradicional con _hereda puede también
características de copia a un modelo nuevo, a pesar de que en una menos manera eficaz.
Esto estuvo hablado en el Añadir características a un Modelo que utiliza receta de herencia.

93
5
Lado de Servidor
básico
Desarrollo
En este capítulo, cubriremos los temas siguientes:
fff
f

f

f

f

f

f

f

f

f


y utilizar el API decorators
D
ef Informando errores al usuario
in Obteniendo un vacío recordset para un
ie
n diffemodelo de alquiler que Crea registros nuevos
d Actualizando valores de recordset
o
m los registros que Buscan registros
ét Combinando recordsets
o
d Filtrando recordsets
o Traversing recordset
s
d relaciones
e Extendiendo la lógica empresarial definida en un
m modelo
o
d Extendiendo escribe() y crear()
el Customizing Cómo los registros están buscados
o

Introducción
En Capítulo 4, Modelos de Aplicación, hemos visto cómo para declarar o extender modelos
empresariales en módulos hechos de encargo. Las recetas en aquella cubierta de capítulo
que escribe métodos para computó campos así como métodos para apremiar tvalora de
campos. Este foco de capítulo en el basics de desarrollo de lado del servidor en Odoo—
definiciones de método, recordset manipulación, y extendiendo heredó métodos.

95
Desarrollo de Lado de Servidor básico

Definiendo métodos de modelo y utilizar


el API decoradores
Las clases de modelo que definen modelos de dato hecho de encargo declaran campos
para el dato procesado por el modelo. También pueden definir comportamiento hecho de
encargo por definir métodos en la clase de modelo.
En esta receta, veremos cómo para escribir un método que se puede apellidar by un botón
en la interfaz de usuario, o por algunos otra pieza de código en nuestra aplicación. Este
método actuará encima
LibraryBooks Y actuar el requirió acciones para cambiar el estado de una selección de libros.

Preparándose
Esta receta supone tienes un instance a punto, con el mi_módulo addon el módulo
disponible, cuando descrito en Capítulo 3, Creando Odoo Módulos. Necesitarás añadir
un campo estatal al LibraryBook el modelo definió como sigue:
De openerp modelos de importación,
campos, api clase
LibraryBook(modelos.Modelo):
# […]
Campos = estatales.Selección([('borrador',
'Inutilizable'),
('disponible',
'Disponible'), ('tomado
prestado', 'Tomado
prestado'), ('perdido',
'Perdido')], estate')

Complacer referir a Capítulo 4, Añadiendo campos de dato a un Modelo para más claridad.

Cómo para hacerlo…


Para definir un method en LibraryBook para dejar cambiando el estado de una selección
de libros, necesitas añadir el código siguiente a la definición de modelo:
1. Añadir un helper método para comprobar si una transición estatal está dejada:
@api.Modelo
def Está_dejado_transición(self, estado_viejo,
estado_nuevo): dejado= [('borrador',
'disponible'),
('Disponible', 'tomado
prestado'), ('tomado
prestado', 'disponible'),
('disponible', 'perdido'),
('tomado prestado',
'perdido'), ('perdido',
'disponible')]
Regreso (estado_viejo, estado_nuevo) en dejó

96
Capítulo 5

2. Añadir un método para cambiar el estado de algunos libros a un nuevos uno pasado
como un argumento:
@api.multi
def Estado_de cambio(self,
estado_nuevo): para libro en
self:
Si book.is_transición_dejada(libro.Estado estatal
,_nuevo):

Libro.Estado =
nuevo_estatal más:
Continúa

Cómo trabaja…
El código en la receta define dos métodos. Son métodos de Pitón normal , habiendo self
como su primer argumento y puede tener argumentos adicionales también.
Los métodos están decorados con decorators del openerp.api Módulo. Estos decorators es allí
para asegurar la conversión de llamadas hizo utilizar el viejo o tradicional API al nuevo API. El
viejo API está utilizado por la llamada de procedimiento remota (RPC) protocolo del cliente de web
y por módulos que no ha sido todavía ported al nuevo API. Una parte clave de esta conversión
esth e creación de un entorno de ejecución almacenado en self.env; Contiene el siguiente:

f self.env.cr: Esto es un cursor de base de datos


f self.env.Usuario: Esto es el usuario ejecutando la acción
fself.env.Contexto: Esto es contexto, el cual es un diccionario de Pitón
containing variasinformación como la lengua del usuario, su huso horario
configurado, y otras llaves concretas que puede ser puesto en tiempo corrido por las
acciones de la interfaz de usuario
Cuándo escribiendo un método nuevo, generalmente serás utilizando @api.multi.
Enadditio n a la creación del entorno, este decorator dice el RPC capa para inicializar self
utilizando el récord IDs suministró en el RPC argumento ids. En tales métodos, self es un
recordset que puede referir a un número arbitrario de registros de base de datos.
El @api.model decorator Es similar pero está utilizado en métodos para qué sólo el modelo es
importante, no los contenidos del recordset, el cual no es actuado a por el método. El concepto es
similar a Pitón @classmethod decorator (pero generalmente no podemos utilizar esto enO doo
modelos porque necesitamos acceso a self.env Y otros atributos de caso importantes).

El @api.Modelo y @api.multi decorators También tener significado


concreto cuándo asegurando la compatibilidad de vuestro addon módulo con
otros módulos todavía utilizando el "viejos API". Encontrarás más información
en este en el Porting viejo API código al nuevo API receta en Capítulo 6,
Desarrollo de Lado de Servidor Adelantado Técnicas.
97
Desarrollo de Lado de Servidor básico

Aquí es una fragmento de código del ejemplo estado de cambio_llamado():


# Libro_regresado_ids es una lista de reservar ids para
regresar libros = self.env['Biblioteca.Libro']
libros.Explora(libro_regresado_ids).Estado_de
cambio('disponible')

Cuándo estado_de cambio() se apellida, self es un (posiblemente vacío) recordset


conteniendo registros de la biblioteca.Modelo de libro. El cuerpo del estado_de
cambio() bucles de método sobre self para procesar cada libro en el recordset. Looping
En self las miradas extrañas al principio, pero conseguirás utilizado a este patrón muy
deprisa.
Dentro del bucle, estado_de cambio() las llamadas está_dejada
transición_(). El call está hecho utilizando el libro variable local, pero pueda
haber sido hecho en cualquier recordset para el
Biblioteca.Modelo de libro, incluyendo, por ejemplo, self, desde entonces
está_dejado_transición() está decorado con @api.Modelo . Si la transición está dejada,
estado_de cambio() asignas el estado nuevo al libro por asignar un valor al atributo del
recordset. Esto es sólo válido en recordsets de longitud 1, el cual es guaranteed para ser el caso
cuándo iterando sobre self.

Allí ha más…
Hay algunos factores importantes que vale entender.

Escondiendo métodos del RPC interfaz


En el viejo API, métodos con un nombre prefijado por un underscore no es expuesto a través
del
RPC Interfaz y es por tanto no callable por el cliente de web. Esto es todavía el caso con el
nuevo API, el cual también ofrece otra manera de hacer un método inutilizable al RPC
interfaz; si no pones un @api.Modelo o @api.multi decorator Encima él (o encima uno
del decorators mencionó en el Porting viejo API código al nuevo API receta en Capítulo 6,
Desarrollo de Lado de Servidor Adelantado Técnicas), entonces el método tampoco será
callable por extensiones del modelo que utiliza el tradicional API ni vía RPC.

El @api.Un decorator
Puedes encontrar el @api.Uno decorator mientras leyendo código de fuente. En Odoo 9.0,
este decorator es deprecated porque su comportamiento puede ser confundir—al principio
mirada, y sabiendo de @api.multi , parece este decorator deja el método para apellidarse
sólo en recordsets de medida 1, pero él no. Cuándo viene a recordset longitud, @api.Uno
es similar a @api. multi, pero él un para bucle en el recordset fuera del método y agrega
el valor regresado de cada iteración del bucle en una lista, el cual está regresado al
llamador. Evita utilizar él en vuestro código.

Ve también
En Capítulo 8, Backend Vistas, refiere a los botones de Añadir para formar receta para
aprender cómo para llamar tal método de la interfaz de usuario.

98
Capítulo 5

Encontrarás información adicional en el decorators definió en openerp.api En la receta


de Capítulo 6, Servidor Adelantado Side Técnicas de Desarrollo: Porting viejo API código al
nuevo API.

Informando errores al usuario


Durante ejecución de método, es a veces necesario de abortar el procesamiento porque
una condición de error estuvo conocida. Estos espectáculos de receta cómo para hacer
este de modo que un helpful mensaje de error está mostrado al usuario cuándo un
método qué escribe un archivo a disco encuentra un error.

Preparándose
Para utilizar esta receta, necesitas un método, los cuales pueden tener una condición
anormal. Utilizaremos el siguientes un:
Importación os
De openerp immodelos portuarios, campos, api

Clase
SomeModel(modelos.Modelo):
campos = de
dato.Texto('Dato')

@api.multi
def Salva(self, filename):
Camino =
os.Camino.Une('/optar/exportaciones',
filename) con abiertos(camino, 'w') cuando
fobj:
Para récord en self:
fobj.Escribe(récord.Dat
o) fobj.Escribe('\n')

Este método puede fallar debido a asuntos de permiso, o un disco lleno, o un nombre
ilegal, el cual causaría un IOError o un OSError excepción para ser levantada.

Cómo para hacerlo…


Para mostrar un mensaje de error al usuario cuándo una condición de error está
encontrada, necesitas tomar los pasos siguientes:
1. Añadir la importación siguiente a principios del archivo de
Pitón: de openerp.Importación de excepciones
UserError
2. Modificar el método para coger la excepción levantada y levantar un UserError
excepción:
@api.multi
def Salva(self, filename):
Si '/' en filename o '\\' en filename:

99
Desarrollo de Lado de Servidor básico
Levanta UserError('Ilegal filename %s' % filename)
camino = os.Camino.Une('/optar/exportaciones', filename)
Prueba:
Con abierto(camino, 'w')
cuando fobj: para récord
en self:
fobj.write(Récord.Dato)
fobj.Escribe('\n')
exceptúa (IOError, OSError) cuando
exc:
Mensaje = 'Incapaz de salvar archivo:
%s' % exc levanta UserError(mensaje)

Cómo trabaja…
Cuándo una excepción está levantada en Pitón, propaga arriba de la llamada stack hasta que
está procesado. En Odoo, tél RPC capa que respuestas las llamadas hicieron por el cliente de web
coge todas las excepciones y, dependiendo de la clase de excepción, provoque comportamientos
posibles diferentes en el cliente de web.

Cualquier excepción no definida en openerp.Las excepciones serán manejadas como


un Error de Servidor Interno (estado de HTTP 500), con el stack rastro. Un UserError
mostrará un mensaje de error en la interfaz de usuario. El código de la receta cambia el
OSError a un UserError para asegurar el mensaje está mostrado en una manera
amistosa. En todos los casos, the transacción de base de datos actual está rodada atrás.

Naturalmente, no es requerido para coger una excepción con un probar..Exceptúa,


construye para levantar un UserError excepción. Es perfectamente VALE para probar
para alguna condición, como la presencia de caracteres ilegales en un filename, y para
levantar la excepción cuándo aquella prueba es Cierta. Esto impedirá procesamiento
más lejano de la petición de usuario.

Allí ha más…
hay unos cuantos más clases de excepción definieron en openerp.Excepciones, todo
derivando el legado de base excepto_orm clase de excepción. La mayoría de ellos es sólo
utilizado internamente, aparte del siguiente:
f Aviso: En Odoo 8.0, openerp.Excepciones.El aviso jugó la función de
UserError En 9.0. Es ahora deprecated porque el nombre era engañoso ( es un
error , no un aviso) y él collided con la Pitón construida-en Advertir clase. Está
mantenido para backward compatibilidad sólo y tendrías que utilizar UserError
en 9.0.
fValidationError: Esta excepción está levantada cuándo un constreñimiento
de Pitón en un campono es respetado. En Capítulo 4, Aplicación Models, refiere
al constreñimiento de Añadir validaciones a una receta de Modelo para más
información.
100
Capítulo 5

Obteniendo un vacío recordset para un


modelo diferente
Cuándo escribiendo Odoo código, los métodos del modelo actual son disponibles vía self.
Siy ou necesidad de trabajar en un modelo diferente, no es posible a directamente
instantiate la clase de aquel modelo— necesitas conseguir un recordset para aquel modelo
para empezar laborable.
Estos espectáculos de receta cómo para conseguir un vacío recordset para cualquier
modelo registrado en Odoo dentro de un método de modelo.

Preparándose
Esta receta reutilización el setup del ejemplo de biblioteca en el addon módulo mi_módulo.

Escribiremos un método pequeño en la biblioteca.Modelo de libro que busca toda


biblioteca. Miembros. Para hacer este, necesitamos conseguir un vacíos recordset
para biblioteca.Miembros.

Cómo para hacerlo…


Para conseguir un recordset para biblioteca.Miembros en un método de
biblioteca.Libro , necesitas tomar los pasos siguientes:
1. En el LibraryBook clase, escribir un método llamó
conseguir_todos_miembros_de biblioteca:
Clase LibraryBook(modelos.Modelo):
# ...
@api.Modelo
def Consigue_todos_miembros_de biblioteca(self):
# ...

2. En el cuerpo del método, uso el código siguiente:


Modelo_de miembro_de la biblioteca =
self.env['Biblioteca.Miembro'] modelo de
miembro_de biblioteca_de regreso.Búsqueda([])

Cómo trabaja…
En empezar arriba, Odoo carga todo el modules y combina las varias clases que derivan de
Modelo y definiendo o extendiendo un modelo dado. Estas clases están almacenadas en
el Odoo registro indexed por nombre. El entorno en self.env Proporciona un acceso de
atajo al registro por emular una Pitón dictionary; si sabes el nombre del modelo estás
buscando, self.env[Nombre_de modelo] te conseguirá un vacío recordset para aquel
modelo. Además, el recordset compartirá el entorno de self .
La llamada para buscar() está explicado en los registros de Buscar receta más tarde.

101
Desarrollo de Lado de Servidor básico

Ve también
El Cambiando el usuario que actúa una acción y Llamando un método con un modificado
enviroment recetas en Capítulo 6, Desarrollo de Lado de Servidor Adelantado Técnicas, trata
modificar self.env en runtime.

Creando registros nuevos


Una necesidad frecuente cuándo escribiendo métodos de lógica empresarial es para crear
registros nuevos. Esta receta explica cómo para crear registros del res.Modelo de socio, el
cual está definido en Odoo base addon módulo. Crearemos una parte nuevaner representando
una compañía, con algunos contactos.

Preparándose
Necesitas saber la estructura de los modelos para qué quieres crear un registro,
especialmente sus nombres y tipos así como cualesquier constreñimientos que existen en
estos campos (por ejemplo, si algunos de ellos son obligatorios). El res.Modelo de socio
definido en Odoo tiene un número muy grande de campos, y para mantener las cosas
sencillas, sólo utilizaremos unos cuantos de estos. Además, la definición de modelo en Odoo
usos el viejos API. Para ayudar sigues la receta, aquí is un puerto de la definición de modelo
seremos utilizar para el nuevos API:
Clase
ResPartner(modelos.Modelo):
_el nombre = ess.Socio'
Campos = de nombre.Char('Nombre',
requerido=Cierto) campos = de
email.Char('Email')
Campos = de fecha.Fecha('Fecha')
Es_campos = de compañía.Booleano('Esun c ompany')
Padre_id = campos.Muchos2un( ess.Socio', eslated Compañía')
niño_ids = campos.Uno2muchos( ess.Socio', 'padre_id',
'Contactos')

Cómo para hacerlo…


Para crear un socio con algunos contactos, necesitas tomar los pasos siguientes:

1. Dentro del método que necesidades de crear un socio nuevo, conseguir la fecha
actual formatted como la cuerda esperada por crear():
Hoy_str = campos.Fecha.Contexto_hoy()

2. Preparar un diccionario de valores para los campos del primer contacto:


val1 = {'nombre': u'Eric Idle',
'emAqueja':
u'eric.idle@example.com' 'fecha':
hoy_str}

102
Capítulo 5

3. Preparar un diccionario de valores para los campos del segundo contacto:


val2 = {'nombre': u'John Cleese',
'Email': u'john.cleese@example.com',
'fecha': hoy_str}

4. Preparar un dictionary de valores para los campos de la compañía:


Socio_val = {
'Nombre': u'Circo de Vuelo',
'email': u
soy.python@example.com', 'fecha':
hoy_str,
'Es_compañía': Cierto,
'niño_ids': [(0, 0, val1),
(0, 0, val2),
]
}

5. Llamada el crear() método para crear los registros nuevos:


Récord = self.env[ Ess.Socio'].Crea(socio_val)

Cómo trabaja…
Para crear un registro nuevo para un modelo, podemos llamar el crear(valores)
método en cualquier recordset relacionó al modelo. Este método regresa un nuevo
recordset de longitud 1 conteniendo el registro nuevo, con los campos valora
especificados en el diccionario de valores.
En el diccionario:

fValores de campo del texto están dados con cuerdas de Pitón (preferentemente
Unicode cuerdas).fFlotadory campode Entero los valores están dados
utilizando flotadores de Pitón o enteros.fBooleanValores de campo están
dados, preferentemente utilizando Pitón booleans o entero.
f Fecha (resp. Datetime) Valores de campo están dados tan cuerdas de Pitón. Campos
de uso.Fecha.
A_cuerda() (resp. fields.datetime.to_Cuerda()) para convertir una
Pitón datetime.Fecha (resp. datetime.datetime) Objeto al formato
esperado.
fValoresde campo binario están pasados como Base64 cuerda codificada. La
base64módulode la Pitón la biblioteca estándar proporciona métodos como
encodestring(s) para codificar una cuerda en Base64.
fMuchos2uncampo los valores son given con un entero, el cual tiene que ser la
base de datos ID de el registro relacionado.
103
Desarrollo de Lado de Servidor básico

fUn2muchosy Muchos2muchoscampos utilizan una sintaxis especial. El valor


es una lista conteniendotuples de tres elementos, como sigue:

Tuple Efecto
(0, 0, dict_val) Crear un registro nuevo que será relacionado al registro principal
(6, 0, id_lista) Crear una relación entre el ser récord creado y existiendo
Registros, cuyo IDs es en la lista de Pitón id_lista
Amonestación: Cuándo utilizado en un Un2muchos, esto sacará
los registros
De cualquier relación anterior

En la receta, creamos los diccionarios para dos contactos en la compañía queremos crear,
y entonces utilizamos estos diccionarios en el niño_ids entrada del diccionario para el
ser de compañía created, utilizando el (0, 0, dict_val) la sintaxis explicó
anteriormente.
Cuándo crear() se apellida en paso 5, tres registros están creados:

f Uno para la compañía de socio principal, el cual está regresado por crear
f Uno para cada de los dos contactos, los cuales son disponibles en récord.Niño_ids

Allí ha más
Si el modelo definió algún default valores para algunos campos, nada de particular
necesita ser hecho; crea() cuidará de computar el default valores para los campos no
presentan en el diccionario suministrado.
Por otro lado, onchange los métodos no son llamados por crear(), porque se apellidan
por el cliente de web durante la edición inicial del registro. Algunos de estos métodos
computan default los valores para campos relacionaron a un campo dado. Cuándo creando
registros a mano tienes que hacer elwo rk tú, cualquiera por proporcionar valores explícitos
o por llamar el onchange métodos. El Llamando onchange métodos en la receta de lado del
servidor en Capítulo 6, Desarrollo de Lado de Servidor Adelantado las técnicas explica cómo
para hacer este.

Actualizando valores de recordset


recordones
La lógica empresarial a menudo significa actualizar registros por cambiar los valores de
algunos de sus campos. Estos espectáculos de receta cómo para añadir un contacto para un
socio y modificar el campo de fecha del socio cuando vamos.
104
Capítulo 5

Preparándose
Esta receta será utilizar el mismo simplificado res.Definición de socio como el Creando
receta de registros nuevos anteriormente. Puedes referir a esta definición simplificada para
saber los campos.

El campo de fecha de res.El socio no ha definido significado en Odoo. Para illustíndice


nuestro propósito, utilizaremos esto para grabar una fecha de actividad en el socio, así que
creando un contacto nuevo tendría que actualizar la fecha del socio.

Cómo para hacerlo…


Para actualizar un socio, puedes escribir un método nuevo llamó añadir_contacto()
definió así:
@api.model
def Añade_contactos(self, socio,
contactos): socio.Asegura_un()
Si contactos:
Socio.Campos = de
fecha.Fecha.Contexto_hoy() socio.Niño_ids
|= contactos

Cómo trabaja…
Los inicios de método por comprobar si el socio pasado como un argumento contiene
exactly uno récord por llamar asegura_un(). Este método levantará una excepción si esto
no es el caso y el procesamiento abortarán. Esto está necesitado, cuando no podemos
añadir los mismos contactos a varios socios al mismo tiempo.

Entonces el método comprueba que los contactos recordset no es vacío, porque no


queremos actualizar la fecha del socio si no estamos modificándolo.
Finalmente, el método modifica los valores de los atributos del registro de socio. Desde
entonces niño_ids es un Un2mucha relación, su valor es un recordset. Utilizamos |=
para computar la unión de los contactos actuales del socio y los contactos nuevos pasaron
al método. Ver la receta siguiente, Combinando recordsets, para más información en estos
operadores.

Nota que ninguna suposición está hecha en self. This El método podría ser definido en
cualquier clase de modelo.

Allí ha más…
Hay tres opciones disponibles si quieres escribir valores nuevos a los campos de registros.

Opción 1 es el explicado en la receta, y trabaja en todos los contextos que—asignan valores


directamente en el atributo que representa el campo del registro. No es posible de asignar
un valor a todo recordset los elementos en uno van, así que necesitas iterar en el recordset,
a no ser que eres seguro que sólo estás manejando un registro solo.

105
Desarrollo de Lado de Servidor básico

Opción 2 es para utilizar la actualización() método por pasar unos nombres de campo de
mapeo de diccionario a los valores quieres puesto. Esto también trabajos únicos para
recordsets de longitud 1. Pueda salvar algunos escribiendo cuándo necesitas actualizar los
valores de several campos inmediatamente en el mismo registro.
Aquí es paso 2 de la receta, reescrito para utilizar esta opción:

@api.Modelo
def Añade_contactos(self, socio,
contactos): socio.Asegura_un()
Si contactos:
Hoy = campos.Fecha.Contexto_hoy()
socio.Actualización(
{'Fecha': today,
'Niño_ids': niño_de socio_ids | contactos}
)

Opción 3 es para llamar el escribir() método, pasando unos nombres de campo de mapeo
de diccionario a los valores quieres puesto. Estos trabajos de método para recordsets de
medida arbitraria y actualizará todos los registros con el specified valores en uno operación de
base de datos sola cuándo las dos opciones anteriores actúan una llamada de base de datos
por récord y por campo. Aun así, tiene algunas limitaciones:

fNo trabaja si los registros no son todavía presentes en la base de datos


(veEscribironchange methods en Capítulo 6, Desarrollo de Lado de Servidor
Adelantado Técnicas para más información en este)
fRequiere utilizar un formato especial cuándo escribiendo campos relacionales,
similares alutilizado por el crear() método

Tuple Efecto
Esto creas un registro nuevo que será relacionado al registro
(0, 0, dict_val) principal.
(1, id, dict_val) Esto actualiza el registro relacionado con el especificado ID con el
Suministró valores.
(2, id) Esto saca el registro con el especificado ID del relacionado
Registros y lo elimina from la base de datos.
(3, id) Esto saca el registro con el especificado ID del relacionado
Registros. El registro no es eliminado de la base de datos.
(4, id) Esto añade un registro de existir con el suministrado ID a la lista de
Relacionó registros.
(5, ) Esto sacas todo el relacionó registros, equivalente a llamar
(3, id) para cada relacionado id.
(6, 0, id_lista) Esto crea una relación entre el ser récord actualizado y el
Existiendo registro, cuyo IDs es en la lista de Pitón id_lista.
106
Capítulo 5

En el tiempo de esta escritura, la documentación oficial es outdated y


menciona que la operación numera 3, 4, 5, y 6 no es disponible encima
Uno2muchos campos, el cual es ya no cierto. Aun así, algunos de estos
no pueden trabajar con Uno2muchos campos, dependiendo de
constraints en los modelos; para caso, si el inverso Mucha2una relación
está requerida, entonces operación 3 fallará porque resulte en un unset
Mucha2una relación.

Buscando registros
Buscando los registros es también una operación común en empresariales logic métodos.
Estos espectáculos de receta cómo para encontrar todas las compañías de Socio y sus
contactos por nombre de compañía.

Preparándose
Esta receta será utilizar el mismo simplificado res.Definición de socio como el Creando
receta de registros nuevos anteriormente. Puedes referir a this simplificó definición para
saber los campos.

Escribiremos el código en un método llamó encontrar_socios_y_contacto(self,


nombre).

Cómo para hacerlo…


Para encontrar los socios, necesitas actuar los pasos siguientes:

1. Conseguir un vacío recordset para res.partner:


@api.Modelo
def Encuentra_socios_y_contactos(self,
nombre): socio = self.env[ Ess.Socio']

2. Escribir el ámbito de búsqueda para vuestros criterios:


Ámbito = ['|',
'&',
('Es_compañía', '=',
Cierto), ('nombre',
'gusta', nombre), '&',
('Es_compañía', '=', Falso),
('padre_id.name', 'gusta',
nombre)
]

3. Llamada la búsqueda() método con el ámbito y regresar el recordset:


Socio de regreso.Búsqueda(ámbito)
107
Desarrollo de Lado de Servidor básico

Cómo trabaja…
Paso 1 define el método. Desde entonces no estamos utilizando los contenidos de self ,
decoramos él con
@api.Modelo, pero esto no es enlazado al propósito de esta receta. Entonces, conseguimos un
vacíos recordset para el res.Modelo de socio porque lo necesitamos para buscar
res.Registros de socio.

Paso 2 crea un ámbito de búsqueda en una variable local. A menudo verás esta creación
inlined en la llamada para buscar, pero con ámbitos complejos, es una práctica buena para
definirlo por separado.
Para una explicación llena de la sintaxis de ámbito de la búsqueda, complacer referir a
los filtros de Definir oficialmente listas: receta de Ámbito en Capítulo 8, Backend Vistas.
Paso 3 llamadas la búsqueda() método con el ámbito. El método regresa un recordset
conteniendo todos los registros que emparejan el ámbito, los cuales entonces pueden
ser más allá procesó. En la receta, llamamos el método con justo el ámbito, pero los
argumentos de palabra clave siguientes son también apoyados:
fOffset=N: Esto suele skip elNprimeros registros que partido la consulta.
Estopuede ser utilizado junto con limitar para implementar paginación o
para reducir consumo de memoria cuándo procesando un número muy grande
of registros. Él defaults a 0 .
f Límite=N: regreso como máximo N registros. Por default, no hay ningún límite.
fEspecificación=de clase_del orden: Esto suele fuerza el orden en el
regresadorecordset. Por default, el orden está dado por el _atributo de orden de
la clase de modelo.
fCuenta=booleano: SiCierto, esto regresa el número de registros en
vez delrecordset. Él defaults a Falso .

Recomendamos utilizar la cuenta_de búsqueda(ámbito) método más que


búsqueda(ámbito, la cuenta=Cierta), cuando el nombre del método
transporta el behavio en una mucha manera más clara; ambos darán el mismo
resultado.

Allí ha más…
Dijimos que la búsqueda() el método regresó todos los registros que emparejan el ámbito.
Esto no es completamente cierto. El método asegura que registros únicos al cual el usuario
que actúa el search tiene el acceso está regresado. Además, si el modelo tiene un campo
booleano llamó activo y ningún plazo del ámbito de búsqueda está especificando una
condición en aquel campo, entonces una condición implícita está añadida por buscar a
regreso único registros=Ciertos activos. Tan si tú expect una búsqueda para regresar
algo pero tú sólo consiguen vacíos recordsets, ser seguro para comprobar el valor del
campo activo (si presente) y para comprobar para reglas récord.
Ver la receta que Llama un método con un contexto diferente en Capítulo 6, Lado de
Servidor Adelantado Development Técnicas para una manera a no tener la condición =
Cierta activa implícita añadió. Ver el Límite el acceso récord que utiliza receta de
reglas récord en Capítulo 10, Accediendo Seguridad para más información sobre reglas de
acceso de nivel récord.
108
Capítulo 5

Si para alguna razón te encuentras escribiendo consultas de SQL crudo para encontrar
récord IDs, ser seguro para utilizar self.env['Registro.Modelo'].Búsqueda([('id',
'en', tuple(ids)).ids Después de recuperar el IDs para hacer seguro que reglas de
seguridad están aplicadas. Esto es especialmente importante en multicompany Odoo
casos donde las reglas récord suelen asegura discriminación apropiada entre compañías.

Combinando recordsets
A veces, encontrarás que te ha obtenido recordsets cuáles no son exactamente qué
necesitas. Esta receta muestra varias maneras de combinarles.

Preparándose
Para utilizar esta receta, necesitas tener dos o más recordsets para el mismo modelo.

Cómo para hacerlo…


Aquí es la manera de conseguir operaciones comunes en recordsets:

1. Para fusionar dos recordsets a uno mientras preservando su order, uso la


operación siguiente:
Resultado = recordset1 + recordset2

2. Para fusionar dos recordsets a uno asegurando que no hay ningún duplicado en el
resultado, uso la operación siguiente:
Resultado = recordset1 | recordset2

3. Para encontrar los registros que es común a dos recordsets, uso la operación
siguiente: resultado = recordset1 & recordset2

Cómo trabaja…
La clase para recordsets implementa varios operador de Pitón redefinitions, los cuales
están utilizados aquí. Aquí es una mesa de resumen de la Pitón más útil operadores then
puede ser utilizado en recordsets:

Operador La acción actuó


Esto regresa un nuevo recordset conteniendo los registros de R1 seguidos por
R1 + R2 el
Registros de R2 . Esto puede generar registros duplicados en el recordset.
Esto regresa un nuevo recordset consisting de los registros de R1 , los cuales no
R1 – R2 son
En R2. El orden está preservado.
109
Desarrollo de Lado de Servidor básico

Operador La acción actuó


Esto regresa un nuevo recordset con todos los registros que pertenece a ambos
R1 & R2 R1 y R2.
(intersection De recordsets). El orden no es preservado aquí.
Esto regresa un nuevo recordset con los registros que pertenecen a cualquier
R1 | R2 R1 o R2.
(Unión de recordsets). El orden no es preservado, pero no hay ningún
duplicado.
R1 == R2 Cierto si ambos recordsets contener los mismos registros.
Cierto si todos los registros en R1 es también en R2. Ambas sintaxis son
R1 <= R2 equivalentes.
R1 En R2
Cierto si todos los registros en R2 es también en R1. Ambas sintaxis son
R1 >= R2 equivalentes.
R2 En R1
R1 != R2 Cierto si R1 y R2 no contain los mismos registros.

hay también en-operadores de sitio +=, -=, &=, y |= , los cuales modifican el operando
izquierdo en vez de crear un nuevo recordset. Estos son muy útiles cuándo actualizando
un registro es
Uno2muchos o Muchos2muchos campos. Ver los valores de Actualizar de
recordset receta de registros anteriormente para un ejemplo.

Allí ha más…
El ordenado() el método ordenará los registros en un recordset. Llamado sin argumentos,
el _atributo de orden del modelo será utilizado. Otherwise, una función puede ser
pasada para computar un comparison llave en la misma moda como la Pitón construida-en
ordenado(secuencia, llave) función. El argumento de palabra clave inverso es
también apoyado.

Nota aproximadamente rendimiento


Cuándo el default _parámetro de orden del modelo está utilizado, el
ordenando está delegado a la base de datos y un nuevo SELECCIONA la
función está actuada para conseguir el orden. Otherwise, el ordenando
está actuado por Odoo. Dependiendo de qué está siendo manipulado, y en
la medida del recordsets, puede haber algunos diferencias de
rendimiento importante.

Filtrando recordsets
En algunos casos, ya tienes un recordset, pero necesitas operar sólo encima algunos
registros. Puedes, naturalmente, itera en el recordset, comprobando para la condición en
cada iteración y suplente dependiendo de el resultado del control. Pueda ser más fácil, y
en algunos casos, más eficaces de construir un nuevos recordset conteniendo sólo los
registros interesantes y llamando una operación sola en aquel recordset.

Estos espectáculos de receta cómo para utilizar el filtro() método para extraer un
recordset de otro.

110
Chapter 5

Preparándose
Nosotros reutilización el simplificado res.Modelo de socio mostrado en el Crear receta
de registros nuevos anteriormente. Esta receta define un método para extraer socios
habiendo una dirección de email de un suministrado recordset.

Cómo para hacerlo…


Para extrregistros de acto con una dirección de email de un recordset, necesitas actuar
los pasos siguientes:
1. Definir el método que acepta el original recordset:
@api.Modelo
def Socios_con_email(self, socios):

2. Definir una función de predicado interior:


def predicate(Socio): si
socio.Email:
Regreso el
regreso Cierto
Falso

3. Filtro de llamada() como sigue:


Socios de regreso.Filtro(predicado)

Cómo trabaja…
La implementación del filtro() método de recordsets crea un vacío recordset en qué
añade todos los registros for cuál la función de predicado evalúa a Cierto . El nuevo recordset
es finalmente regresó. El orden de registros en el originales recordset está preservado.

La receta de preceder utilizó una función interna nombrada. Para tales predicados
sencillos, a menudo encontrarás un unnonymous función de lambda utilizó:
@api.Modelo
def Socios_con_email(self, socios): socios de
regreso.Filtro(lambda p: p.Email)

De hecho, para filtrar un recordset basó en el hecho que uno atribuye es truthy en el sentido
de Pitón, puedes utilizar socios.Filtro('email').

111
Desarrollo de Lado de Servidor básico

Allí ha más…
Mantiene en importar aquel filtro() opera en la memoria. Si estás intentando
optimizar el rendimiento de un método en el camino crítico, puedes querer utilizar
un ámbito de búsqueda o incluso mover a SQL, en el coste de readability.

Traversing recordset Relaciones


Cuándo trabajando con un recordset de longitud 1, los varios campos son disponibles como
atributos récord. Atributos relacionales ( Un2muchos, Muchos2un, y Muchos2muchos ) es
también disponible con valorars aquello es recordsets demasiado. Cuándo trabajando con
recordsets con más de uno récord, los atributos no pueden ser utilizados.

Estos espectáculos de receta cómo para utilizar el mapped() método a traverse recordset
relaciones; escribiremos dos métodos que actúan el siguientes operations:
f Recuperando los emails de todos los contactos de una compañía de socio
sola pasada como un argumento
f Recuperando las varias compañías a qué algunas socias de contacto están
relacionadas

Preparándose
Seremos reusing el modelo de Socio simplificado mostrado en el Crear receta de
registros nuevos de este capítulo.

Cómo para hacerlo…


Para escribir los métodos de manipulación del socio, necesitas actuar los pasos
siguientes:

1. Definir un método llamó conseguir_direcciones_de email():


@api.Modelo
def Consigue_direcciones_de
email(self, socio):
partener.Asegura_un()

2. Llamada mapped() para conseguir las direcciones de email de los contactos del
socio:
Socio de regreso.mapped('Niño_ids.Email')

3. Definir un método llamó conseguir_compañías():


@api.Modelo
def Consigue_compañías(self, socios):
4. Llamada mapped() para conseguirth e compañías diferentes de los socios:
Socios de regreso.mapped('Padre_id')

112
Capítulo 5

Cómo trabaja…
En paso 1, llamamos asegura_un() para hacer seguro tenemos un socio solo. Esto no es
requerido para la receta, cuando mapped() trabaja muy bien en recordsets de medida
arbitraria. Aun así, es mandated por la especificación del método estamos escribiendo,
cuando no queremos recuperar contactos de compañías múltiples por equivocación.

En paso 2 y paso 4, llamamos el mapped(camino) método a traverse los campos del


recordset; el camino es una cuerda conteniendo nombres de campo separaron por
puntos. Para cada campo en el camino, mapped() produce un nuevo recordset conteniendo
todos los registros relacionaron por este campo a todos los elementos en el actuales
recordset y entonces aplica el elemento próximo en el camino en aquel nuevo recordset. Si el
último campo en el camino es un campo relacional, mapped() regresará un recordset;
otherwise, una lista de Pitón está regresada.

El mapped() el método tiene dos propiedades notables:


fSi el camino es un solo escalar field nombre, entonces la lista regresada es en el
mismo orden comoel procesado recordset.
fSi el camino contiene un campo relacional, entonces el orden no es preservado,
pero los duplicados estánsacados del resultado.

Esta segunda propiedad es muy útil en un método decovaloró


con @api.multi donde Quieres actuar una operación encima
todos los registros señalados por un Muchos2mucho campo de
todos los registros en self, pero necesidad de hacer seguro
que la acción está actuada sólo una vez (incluso si dos registros
de self participación el mismo registro de objetivo).

TAquí es más…
Cuándo utilizando mapped(), mantiene en importar que opera en la memoria dentro del Odoo
servidor por repetidamente traversing relaciones y por tanto haciendo consultas de SQL, los
cuales no pueden ser eficaces; aun así, el código es terse y expresivo. Si eres pruebaing para
optimizar un método en el camino crítico del rendimiento de vuestro caso, puedes querer
reescribir la llamada a mapped() y expresar él como búsqueda() con el ámbito apropiado, o
incluso mover a SQL (en el coste
De readability).

El mapped() method también se puede apellidar con una función cuando argumento. En este
caso, regresa una lista que contiene el resultado de la función aplicó a cada registro de self ,
o la unión del recordsets regresó por la función, si la función regresa un recordset.
113
Desarrollo de Lado de Servidor
básico

Ve también
f El Buscar receta de registros
f El Ejecutando receta de consultas de SQL cruda En Capítulo 6, Desarrollo
de Lado de Servidor Adelantado Técnicas

Extendiendo la lógica empresarial definida


en un
Modelo
Cuándo definiendo un modelo que extiende otro modelo, es a menudo necesario de
personalizar el comportamiento de algunos métodos definió en el modelo original. Esto es
una tarea muy fácil en Odoo, y uno de las características más potentes del marco
subyacente.
Demostraremos esto por extender un método que crea registros de añadir un campo
nuevo en el creó registros.

Preparándose
Si quieres seguir la receta, marca seguro tienes el mi_módulo addon de Capítulo 3,
Creando Odoo Módulos, con el brujo de préstamo definido en el Writing un brujo para guiar
la receta de usuario de Capítulo 6, Desarrollo de Lado de Servidor Adelantado Técnicas.
Crear un nuevo addon módulo regreso de préstamo_de
biblioteca_llamado_data aquello depende de mi_módulo. En este módulo,
extender la biblioteca.Libro.Modelo de préstamo como sigue:
Clase
LibraryBookLoan(modelos.Modelo):
_hereda =
'biblioteca.Libro.Préstamo'
Campos_de fecha_de regreso = esperados.Fecha('Previsto para',
requerido=Cierto)

Extender la biblioteca.Modelo de miembro como sigue:


Clase
LibraryMember(modelos.Modelo):
_hereda = 'biblioteca.Miembro'
Duración_de préstamo = fields.integer('duración
de Préstamo',
default=15,
requerido=Cierto
)
Desde el campo_de fecha_de regreso esperado está requerido y ningún default está
proporcionado, el brujo a préstamos récord cesará funcionar porque no proporciona un valor
para aquel campo cuándo crea préstamos.

114
Capítulo 5

Cómo para hacerlo…


Para extender la lógica empresarial en la biblioteca.Préstamo.Modelo de brujo,
necesitas actuar los pasos siguientes:
1. En mi_módulo, modificar el método préstamos_récord() en el
LibraryLoanWizard clase. El código original es en el Writing un brujo para guiar la
receta de usuario en Capítulo 6, Desarrollo de Lado de Servidor Adelantado Técnicas. La
versión nueva es:
@api.multi
def
Préstamos_récord(se
lf): para brujo en
self:
Brujo = de libros .Libro_ids
Préstamo =
self.env['Biblioteca.Libro.Préstamo']
para libro en brujo.Libro_ids:
Valores =
self._Prepara_préstamo(libro)
préstamo.Crea(valores)
@api.multi
def _Prepara_préstamo(self, libro):
El regreso { soy rescoldo_id':
self.member_id.id, 'libro_id':
book.id}

2. En fecha_de regreso_de préstamo_de biblioteca, crear una clase qué


extiende biblioteca.Préstamo. Brujo y demulta el _preparar_método de
préstamo como sigue:
De datetime importación timedelta
De openerp modelos de importación, campos, api
Clase LibraryLoanWizard(modelos.TransientModel):
_Hereda = 'biblioteca.Carga.Brujo'

def _Prepara_préstamo(self, libro):


valores = super(LibraryLoanBrujo,
self
)._Prepara_préstamo(libro)

Duración_de préstamo =
self.Miembro_id.Duración_de préstamo hoy_str
= campos.Fecha.Contexto_hoy() hoy =
campos.Fecha.De_cuerda(hoy_str)
Esperado = hoy + timedelta(duración=de
préstamo_de los días) valores.Actualización(
{'Fecha_de regreso_esperado':
fields.date.to_cuerda(esperado)}
)
Valores de regreso

115
Desarrollo de Lado de Servidor básico

Cómo trabaja…
En paso 1, nosotros refactor el código del Escribiendo un brujo para guiar la receta de
usuario en Capítulo 6, Desarrollo de Lado de Servidor Adelantado Técnicas, para utilizar una
codificación muy común y útil patrón para crear la biblioteca.Libro.Registros de préstamo: la
creación del diccionario de valores está extraído en un método separado más que hardcoded
en el método que llama crea(). Esto alivia extender el addon módulo in caso los valores
nuevos tienen que ser pasados en tiempo de creación, el cual es exactamente el caso
estamos afrontando.
Paso 2 entonces hace la extensión de la lógica empresarial. Definimos un modelo que
extiende biblioteca.Préstamo.Brujo y redefine el _preparar_préstamo()
método. El redefinitinicios de ión por llamar la implementación de la clase de padre:
Valores = super(LibraryLoanWizard, self)._Prepara_préstamo(libro)

En el caso de Odoo modelos, la clase de padre no es qué esperarías por mirar en el


Definición de clase de la pitón. El marco has dinámicamente generó una jerarquía de clase
para nuestro recordset, y la clase de padre es la definición del modelo de los módulos
encima cuál dependemos. Así que la llamada a super() trae atrás la implementación de
biblioteca.Préstamo.Brujo de mi_módulo . En este implementation,
_prepara_préstamo() regresa un diccionario de valores con soyrescoldo_id' y
'libro_id' . Actualizamos este diccionario por añadir el 'fecha_ de regreso_esperado'
clave antes de regresarlo.

Allí ha más…
En esta receta, escogimos extender el comportamiento por llamart él implementación
normal y modificando el resultado regresado después. Es también posible de actuar
algunas acciones antes de llamar la implementación normal, y naturalmente, también
podemos hacer ambos.
Aun así, qué vimos en esta receta es que es más duro a change el comportamiento del medio
de un método. Tuvimos que refactor el código para extraer un punto de extensión a un método
separado y override este método nuevo en el módulo de extensión.

Puedes ser tentado a completamente reescribir un método. Siempre ser


muy cauteloso cuándo haciendo tan—si no llamas el super()
implementación de vuestro método, estás rompiendo el mecanismo de
extensión y potencialmente rompiendo addons para qué su extensión del
mismo método nunca se apellidará. A no ser que estás trabajando en un
controlado environment, en qué sabes exactamente qué addons es
instalado y has comprobado que no estás rompiéndoles, evita hacer este.
Y si tienes que, ser seguro para documentar qué estás haciendo en una
manera muy visible.
116
Capítulo 5

Qué puede you hacer antes y después de llamar la implementación original del método?
Muchas cosas, incluyendo (pero no limitados a):
fModificando los argumentos que está pasado a la implementación original
(antes)fModificando el contexto que está pasado al original implementación
(antes)
fModificando el resultado que está regresado por la implementación
original (después)fLlamando otro método (antes, después)
f Creando registros (antes, después)
f Levantando un UserError para cancelar la ejecución en casos prohibidos (before,
después)
fPartiendoselfen más pequeño recordsets, y llamando la implementación
original en cadade los subconjuntos en una manera diferente (antes)

Extendiendo escribe() y crear()


El Extendiendo la lógica empresarial definida en una receta de Modelo mostrada
cómo a extender los métodos definieron en una clase de modelo. Si piensas
aproximadamente lo, los métodos definieron en la clase de padre del modelo es
también parte del modelo. Esto significa que todos los métodos de base definieron en
modelos.Modelo (de hecho en modelos.BaseModel, El cual es la clase de padre
de modelos.Modelo ) es también disponible y puede ser extendido.

Estos espectáculos de receta cómo para extender crear() y escribir() para controlar
acceso a algunos campos de los registros.

Preparándose
Extenderemos en el ejemplo de biblioteca del mi_módulo addon módulo en Chapter 3,
Creando Odoo Módulos.

También necesitarás los grupos de seguridad definieron en Capítulo 10, Accediendo


Seguridad en el
Creando Grupos de seguridad y asignándoles a receta de Usuarios y los derechos de
acceso definieron en la seguridad de Añadir acceso a receta de modelos del mismo
capítulo.

Modificar la seguridad de archivo/ir.Modelo.Acceso.csv Para dar escribir


acceso a usuarios de biblioteca a libros:
id,nombre,modelo_id:id,grupo_id:id,perm_leído,perm_escribe,perm_crea,
perm_ unlink usuario_de libro_de biblioteca_de
acceso,biblioteca.Libro.Usuario,abucheo_de biblioteca_del
modelok,base. Usuario_de grupo,1,1,0,0 biblioteca_de
acceso_libro_admin,biblioteca.Libro.admin,libro_de biblioteca_del
modelo,base. Sistema_de grupo,1,0,0,0
117
Desarrollo de Lado de Servidor básico

Añadir unos comentarios de director_del campo a la biblioteca.Modelo de libro.


Queremos miembros únicos del
Grupo de Directores de la biblioteca para ser capaz de escribir a aquel campo:

Clase
LibraryBook(modelos.Modelo):
_nombre = 'biblioteca.Libro'
Campos_de comentarios = del director.Texto( soyanager Remarca')

Cómo para hacerlo…


Para impedir usuarios quiénes no son miembros del grupo de Directores de la Biblioteca de
modifying el valor de comentarios_de director , necesitas actuar los pasos siguientes:
1. Extender el crear() método así:
@api.Modelo
@api.Regresos( eselfo', lambda rec:
rec.id) def crear(self, valores):
Si no self.El usuario_tiene_grupos( 'biblioteca.Biblioteca_de
grupo_manager'):

Sisoyanager_remarca' en
valores: levanta
excepciones.UserError(
'No eres dejado para modificar '
soyanager_remarca'
)
Regreso super(LibraryBook, self).Crea(valores)

2. Extender el escribir() método como sigue:


@api.multi
def Escribe(self, valores):
if No self.El usuario_tiene_grupos( 'biblioteca.Director_de

biblioteca_del grupo'):

Sisoyanager_remarca' en
valores: levanta
excepciones.UserError(
'No eres dejado para modificar '
soyanager_remarca'
)
Regreso super(LibraryBook, self).Escribe(valores)

3. Extender los campos_consiguen() conocióhod como sigue:


@api.Modelo
def Los campos_consiguen(self,
allfields=Ninguno,
escribe_el
acceso=Cierto,
atribuye=Ninguno):
Campos = super(LibraryBook, self).Los campos_consiguen(

118
Capítulo 5
allfields=allfields, escribe_el
acceso=escribe_acceso,
atributos=de atributos
)
Si no self.El usuario_tiene_grupos( 'biblioteca.Director_de
biblioteca_del grupo'):

Si soyanager_remarca' en campos: campos[


soyanager_remarca'][ esadonly'] = Cierto

Cómo trabaja…
Paso 1 redefine el crear() método. Utiliza un decorator no hemos visto tan lejos,
@api.Regresos.

Este decorator mapas el valor regresado del nuevo API al viejo API, el
cual está esperado por el RPC protocolo. En este caso, el RPC llamadas
para crear esperan la base de datos id para el registro nuevo de ser
creado, así que pasamos el @api.Regresos decorator un anónimos
functión, el cual fetches el id del registro nuevo regresado por nuestra
implementación. Es también necesitado si quieres extender la copia()
método. No Lo olvida cuándo extendiendo estos métodos si la
implementación de base utiliza el viejo API o chocarás con duro to
interpretar mensajes.

Antes de llamar la implementación de base de crear() , nuestro método utiliza el


usuario_tiene_ grupos() método para comprobar si el usuario pertenece a la
biblioteca de grupo.Director_ de biblioteca_del grupo (esto es el XML ID del
grupo). Si no es el caso y un valor está pasado para comentarios_de director, un
UserError la excepción está levantada impidiendo la creación del registro. Este control
está actuado antes de la implementación de base se apellida.
Paso 2 la misma cosa para el escribir() método; antes de escribir, comprobamos el grupo
y la presencia del campo en los valores para escribir y levantar UserError si hay un problema.

Paso 3 es una bonificación pequeña; los campos_consiguen() el método está utilizado


por el cliente de web a consulta para los campos del modelo y sus propiedades. Regresa
unP ython nombres de campo de mapeo de diccionario a un diccionario de atributos de
campo, como la cuerda de exhibición o la cuerda de ayuda. Qué nos intereso es el
readonly atributo, el cual forzamos a Ciertos si el usuario no es un director de biblioteca.
Esto hará el campo leído sólo en el cliente de web, el cual evitará usuarios no autorizados de
probar para editarlo sólo para estar frente a un mensaje de error.

Teniendo el campo puesto para leer-único en el cliente de web no impide


RPC llamadas de escribirlo. Esto es por qué nosotros extiende crear()
und escribir().
119
Desarrollo de Lado de Servidor básico

Allí ha más…
Cuándo extendiendo escribe(), nota que antes de llamar el super() implementación de
escribir() , self es quieto unmodified. Puedes utilizar esto para comparar los valores
actuales de los campos a los en el diccionario de valores.
En la receta, escogimos levantar una excepción, pero podríamos haber también sacó el campo
de ofender del diccionario de valores y silenciosamente skipped actualizando que campo en el
registro:
@api.multi
def Escribe(self, valores):
Si no self.El usuario_tiene_grupos( 'biblioteca.Director_de
biblioteca_del grupo'):

Sisoyanager_remarca' en valores:
del Valores[ soyanager_remarca']
Regreso super(LibraryBook, self).Escribe(valores)

Después de llamar super().Escribe(), si quieres actuar acciones adicionales,


hast o ser cauto de cualquier cosa aquello puede causar otra llamada para
escribir(), o crearás un bucle de recursión infinito. El workaround es para poner un
marcador en el contexto para ser comprobado para romper la recursión:
Clase
MyModel(modelos.Modelo):
@api.multi
def Escribe(self, values):
super(MyModel,
self).Escribe(valores)
Si self.env.Contexto.Consigue(
soyyModelLoopBreaker'): regreso
self =
self.Con_contexto(MyModelLoopBreaker=Cierto)
self.Computa_cosas() # puede causar llamadas a
escribe

Personalizando cómo los registros están


buscados
El Definiendo elMo del representación y receta de orden en Capítulo 3, Creando Odoo los módulos
introdujeron el nombre_consigue() método, el cual suele computar una representación del
registro en varios sitios, incluyendo en el widget utilizó para mostrar Muchos2una relaciones en la
web client.

Estos espectáculos de receta cómo para dejar buscando un libro en el Muchos2un


widget por título, autor, o ISBN por redefinir búsqueda_de nombre.
120
Capítulo 5

Preparándose
Para esta receta, seremos utilizar la definición de modelo siguiente :

Clase
LibraryBook(modelos.Modelo):
_nombre = 'biblioteca.Libro'
Campos = de
nombre.Char('Título') isbn =
campos.Char('ISBN')
Autor_ids = campos.Muchos2muchos( ess.Socio', 'Autores')

@api.Modelo
def El
nombre_consigue
(self):
resultado = []
Para libro en self:
Libro = de
autores.Autor_ids.mapped('Nombre') nombre
= u'%s (%s)' % (libro.Título,
u', '.Une(autores))
resultado.Anexa((book.id, nombre))
Resultado de regreso

Cuándo utilizando este modelo, un libro en un Muchos2un widget está mostrado tan Título de
Libro (Autor1, Autor2...). Los usuarios esperan ser capaces de escribir en un autor name y
encontrar la lista filtrada según este nombre, pero esto no trabajará como el default
implementación de búsqueda_de nombre sólo utiliza el atributo refirió a por el
_rec_atributo de nombre de la clase de modelo, en nuestro caso,
'Nombre'. Como servicio al adelantó usuarios, también queremos dejar filtrando por ISBN
número.

Cómo para hacerlo…


Para dejar buscando biblioteca.Libro tampoco por título de libro, uno de los autores, o
ISBN, necesitas definir la _búsqueda_de nombre() método en el LibraryBook clase como
sigue:
@api.Modol
def _Búsqueda_de nombre(self, nombre='', args=Ninguno,
operador='ilike', límite=100, el
nombre_consigue_uid=Ninguno):
args = [] Si args es Ninguno más args.Copia()
si no(nombre == '' y operador == 'ilike'):
args += ['|', '|',
('Nombre', operador, nombre),
('isbn', operador, nombre),
('author_ids.name', operador, nombre)
]
Regreso super(LibraryBook, self)._Búsqueda_de nombre(
nombre='', args=args, operador='ilike', límite=de
límite, el nombre_consigue_uid=el
nombre_consigue_uid)

121
Desarrollo de Lado de Servidor básico

Cómo trabaja…
El default implementación de nam e_búsqueda() de hecho sólo llama la _búsqueda_de
nombre() método, el cual el trabajo real. Esta _búsqueda_de nombre() el método tiene un
argumento adicional, el nombre_consigue_uid, el cual está utilizado en algunos casos de
esquina para computar los resultados que utilizan sudo().

Pasamos la mayoría de los argumentos tsombrero recibimos sin cambios al super()


implementación del método:
f El nombre es una cuerda conteniendo el valor el usuario ha escrito tan lejos
fargsEs tampocoNingunoo un ámbito de búsqueda utilizado como prefilter para los
registros posibles (pueda provenir el ámbito parameter del Mucha2una relación para
caso)
f El operador es una cuerda conteniendo el operador de partido. Generalmente,
tendrás
'ilike' O '='.
f El límite es el número máximo de filas para recuperar
fEl nombre_consigue_uidpuede soler especificar un usuario diferente
whenel nombre_consigue()enel fin para computar las cuerdas
para mostrar en el widget
Nuestra implementación del método el siguiente:

1. Genera una lista vacía nueva si args es Ninguno, o hace una copia de args otherwise.
Hacemos una copia para evitar nuestro modifications a la lista habiendo efectos de lado
en el llamador.
2. Entonces, comprobamos si el nombre no es una cuerda vacía o si el operador no es
'ilike'. Esto es para evitar generando un ámbito mudo [('nombre', ilike, '')]
que
No filtra cualquier cosa. En aquel caso, saltamos straight a la llamada al
super() implementación.
3. Si tenemos un nombre, o si el operador no es 'ilike', entonces añadimos
algunos filtrando criterios a args . En nuestro caso, añadimos cláusulas que buscará
el nombre suministrado en el título de los libros, o en su ISBN, o en los autores'
nombres.
4. Finalmente, llamamos el super() implementación con el ámbito modificado en
args y forzando nombre a '' y operador a ilike . Nosotros esto para forzar el
default implementación de _búsqueda_de nombre() a no alterar el ámbito recibe,
so el especificamos es para ser utilizado.
122
Capítulo 5

Allí ha más…
Mencionamos en la introducción que este método está utilizado en el Muchos2un
widget. Para completeness, es también utilizado en las partes siguientes de Odoo:
f Propuestas ent busque widget
fCuándo utilizando elenoperador encimaUno2muchosy
Muchos2muchoscampos en el ámbitofpara buscar registros
enmuchos2muchas_etiquetaswidget
f Para buscar registros en el CSV importación de archivo

Ve también
El Definir la Representación de Modelo y receta de Orden en Capítulo 3, Creando Odoo los
módulos presenta cómo para definir el nombre_consigue() método, el cual suele crear
una representación de texto de un registro.
Los filtros de Definir oficialmente listas: receta de Ámbito en Capítulo 8, Backend las vistas
proporciona más información unbout sintaxis de ámbito de la búsqueda.
123
6
Adelantado
Lado de servidor
Desarrollo
Técnicas
En este capítulo, veremos cómo a:

f Cambio el usuario que actúa una acción


f Llamada un método con un contexto
modificado
f
Ejecuta consultas de SQL crudo
f

f
Escribir un brujo para guiar el usuario

f
Define onchange métodos

f
Llamada onchange métodos en el lado de
servidor Portuario viejo API código al
nuevo API

Introducción
En Capítulo 5, Desarrollo de Lado de Servidor Básico, vimos cómo para escribir métodos en
una clase de modelo, cómo para extender métodos de heredó modelos, y cómo para trabajar
con recordsets. Este capítulo trata más adelantó temas como laborables con el entorno de
un recordset y trabajando con onchange métodos.
125
AdelantadoSe rver Técnicas de Desarrollo del Lado

Cambio el usuario que actúa una acción


Cuándo escribiendo código de lógica empresarial, puedes tener que actuar algunas
acciones con un contexto de seguridad diferente. Un caso típico está actuando una acción
con los derechos del Administrador, quién bypasses controles de seguridad.
Estos espectáculos de receta cómo para dejar los usuarios normales modifican el número
de teléfono de una compañía por utilizar sudo().

Preparándose
Seremos trabajar en registros del res.Modelo de compañía. Por default, miembros
únicos del Acceso/de Administración Rights grupo de usuario puede modificar registros
de res.Compañía , pero en nuestro caso, necesitamos proporcionar un punto de acceso
para cambiar sólo el número de teléfono a usuarios quiénes no son necesariamente
miembros de aquel grupo.

Cómo para hacerlo…


Para dejar los usuarios normales modifican el teléfono number de una compañía, necesitas
actuar los pasos siguientes:

1. Definir un modelo que extiende el res.Modelo de compañía:


Clase
ResCompany(modelos.Modelo):
_hereda = ess.Compañía'

2. Añadir un método número de teléfono_de actualización_llamado():


@api.multi
def Número_de teléfono_de la actualización(self, new_número):

3. En el método, asegura estamos actuando en un registro solo:


self.Asegura_un()

4. Modificar el usuario del entorno:


Compañía_como_superuser = self.sudo()

5. Escribir el número de teléfono nuevo:


Compañía_como_superuser.Teléfono = número_nuevo
126
Capítulo 6

Cómo trabaja…
En paso 4, llamamos self.sudo(). Este método regresa un nuevo recordset con un
entorno nuevo en qué el usuario no es igual cuando el en self. Cuándo llamado sin un
argumento, sudo() enlazará el Odoo superuser, Administrator, al entorno. Todas llamadas
de método vía el regresados recordset está hecho con el entorno nuevo, y por tanto con
superuser privilegios.
Si necesitas un usuario concreto, puedes pasar cualquiera un recordset conteniendo
que usuario o la base de datos id delu ser. La fragmento siguiente te dejas para buscar
libros que es visible, utilizando el usuario público:
Usuario_público = self.env.ref('Base.Usuario_público')
libro_público =
self.env['Biblioteca.Libro'].sudo(Usuario_público)

Amonestación cuándo utilizando sudo()


hay no traceability of la acción; el autor de la última modificación de la
compañía en nuestra receta será Administradora, no el usuario
originalmente llamando número_de teléfono_de la
actualización.
El comunitario addon, la base_suspende_seguridad,
encontrado en https://github.com/oca/server-tools/
puede soler trabajo alrededor de esta limitación.

hay más…
Cuándo utilizando sudo() sin un argumento, pusiste el usuario del contexto al Odoo superuser.
Este superuser bypasses todas las reglas de seguridad de Odoo, both las listas de control del
acceso y las reglas récord. Por default, este usuario también tiene una compañía_id el campo
puesto a la compañía principal del caso (el con id 1). Esto puede ser problemático en un multi
caso de compañía:
f Si no eres prudente, nuevo records creó en este entorno será enlazado a la
compañía del superuser
f Si no eres prudente, graba buscado en este entorno puede ser enlazado a cualquier
presente de compañía en la base de datos, el cual significa que puedes ser filtrar
información al real usuario, o peor, puedes ser silenciosamente corrompiendo la
base de datos por enlazar los registros juntos que pertenecen a compañías
diferentes
Utilizando sudo() también implica crear un caso de Entorno nuevo. Este entorno tendrá
un inicialmente vacío recordset cache, y que cache evolucionará independientemente del
cache de self.env . Esto puede causar spurious consultas de base de datos. De todas
formas, tendrías que evitar crear entorno nuevo dentro de bucles, e intentar mover estas
creaciones de entorno al outmost alcance posible.
127
Desarrollo de Lado de Servidor adelantado Técnicas

Ve también
fElObtener un vacío recordset para una receta de modelo enCapítulo
5,Desarrollo de Lado de ServidorBásico, explica lo que el entorno es.

Llamada un método con un contexto


modificado
El contexto es part del entorno de un recordset. Suele información de pase como el timezone o la
lengua del usuario de la interfaz de usuario así como los parámetros contextuales especificaron
en acciones. Un número de métodos en el estándares addons utilizar el contexto to adapta su
comportamiento a estos valores. Es a veces necesario de modificar el contexto en un recordset
para conseguir el deseó resultados de una llamada de método o el valor deseado para un campo
computado.

Estos espectáculos de receta cómo para leer el nivel accionario para todo
producto.product Modelos en un stock dado.Ubicación.

Preparándose
Esta receta utiliza el accionario y producto addons. Para nuestros propósitos, aquí
es una versión simplificada del producto.Modelo de producto:
Producto de
clase.Producto(modelos.Modelo):
_nombre = 'producto.Producto'
Nombre = fields.Char('Nombre', requerido=Cierto)
qty_campos = disponibles.Flotador('Cantidad a
mano',
Computa='_el producto_disponible')
def _El producto_disponible(self):
"""Si el contexto contiene una 'ubicación' clave
enlazada a una base de datos id, entonces el accionario
disponible está computado dentro de aquella ubicación
sólo. Otherwise El stock de todas las ubicaciones
internas está computado"""
El pase # leído la fuente real en addons/stock/product.py :)

Intencionadamente no proporcionamos la implementación de la computación y nosotros


skipped unas cuantas otras llaves que está miradofo r en el contexto para foco en la
receta.

Cómo para hacerlo…


Para computar los niveles accionarios en una ubicación dada para todos los
productos, necesitas actuar los pasos siguientes:

1. Crear una clase de modelo que extiende producto.Producto:


Clase ProductProduct(modelos.Modelo):
_hereda = 'producto.Producto'

128
Capítulo 6

2. Añadir un método stock llamado_en_ubicación():


@api.Modelo
def Stock_en_ubicación(self, ubicación):

3. En el método, conseguir un producto.Producto recordset con un contexto


modificó como sigue:.
product_En_loc = self.Con_contexto(
ubicación=location.id, la
prueba_activa=Falsa

4. Búsqueda todos los productos:


Todo_producto = de productos_en_loc.Búsqueda([])

5. Crear una variedad con el nombre de producto y nivel accionario de todo presente
de productos en la ubicación especificada:
Accionario_levels = []
Para producto en todos los
_productos: si
producto.qty_Disponible:
Niveles_accionarios.Anexa((product.name,
producto.qty_Disponible)
)
Regreso niveles_accionarios

Cómo trabaja…
Paso 3 llamadas self.Con_contexto() con algunos argumentos de palabra clave.
Esto regresa una versión nueva de se lf (cuál es un producto .Producto recordset)
con las llaves añadieron al contexto actual. Estamos añadiendo dos llaves:
fUbicación: Esto uno está mencionado en el docstring
delproducto.Métodode producto que computa el qty_campo
disponible.
fPrueba_activa: Cuándo este key es presente y enlazado alvalorFalso, la
búsqueda() el método no automáticamente añade ('activo', '=',
Cierto) al ámbito de búsqueda. Utilizando este asegura que en paso 4,
conseguimos todos los productos , incluyendo el discapacitados unos.

Cuándo leímos el valor de producto. qty_Disponible en paso 5, la computación de


aquel campo está hecha utilizando sólo la ubicación accionaria especificada.
129
Desarrollo de Lado de Servidor adelantado Técnicas

Allí ha más…
Es también posible de pasar un diccionario a self.Con_contexto() , en which caso el
diccionario está utilizado como el contexto nuevo, overwriting la corriente un. Tan paso 3
también podría haber sido escrito así:
Contexto_nuevo = self.env.Contexto.Copia()
contexto_nuevo.Actualización({'ubicación':
location.id,
'Prueba_activa': Falso})
producto_en_loc =
selfo.Con_contexto(contexto_nuevo)

Utilizando con_contexto() implica crear un caso de Entorno nuevo. Este entorno


tendrá un inicialmente vacío recordset cache, y que cache evolucionará independientemente
del cache de self.env . Esto puede causar spurious consultasde base del dato. De todas
formas, tendrías que evitar crear entornos nuevos dentro de bucles e intentar mover estas
creaciones de entorno al outmost alcance posible.

Ve también
f El Obtener un vacío recordset para una receta de modelo en Capítulo 5, Básico
Server Desarrollo de Lado, explica lo que el entorno es
f Los parámetros de Paso a formas y acciones: receta de Contexto en Capítulo 8,
Backend Vistas, explica cómo para modificar el contexto en acción definiciones
f El Buscar receta de registros en Capítulo 5, Básico Server Desarrollo de Lado,
explica registros activos

Ejecuta consultas de SQL crudo


La mayoría del tiempo, puedes actuar las operaciones quieres utilizar la búsqueda()
método. Aun así, a veces, necesitas más—tampoco no puedes expresar qué quieres utilizar
el ámbito synthacha, para qué algunas operaciones son delicadas si no downright
imposibles, o vuestra consulta requiere muchos llama para buscar(), el cual acaba ser
inefficient.

Esta receta te muestras cómo para utilizar consultas de SQL crudo para leer
res.Registros de socio agruparon por país.

Consigueting a punto
Seremos utilizar una versión simplificada del res.Modelo de socio:
Clase
ResPartner(modelos.Modelo):
_el nombre = ess.Socio'
Campos = de nombre.Char('Nombre', requerido=Cierto)

130
Capítulo 6
Campos = de email.Char('Email')
Es_campos = de compañía.Booleano('Es una compañía')
Padre_id = campos.Muchos2un( ess.Socio', eslated Compañía')
niño_ids = campos.Uno2muchos( ess.Socio', 'padre_id',
'Contactos')
País_id = campos.Muchos2un( ess.País', 'País')

Cómo para hacerlo…


Para escribir un método que regresos un dictionary aquello contiene el mapped nombres de
países a un recordset de todos los socios activos de aquel país, necesitas actuar los pasos
siguientes:
1. Escribir una clase que extiende res.Socio:
Clase
ResPartner(modelos.Modelo):
_hereda = ess.Socio'

2. Añadir un conocidohod llamó socios_por_país():


@api.Modelo:
def Socios_por_país(self):

3. En el método, escribir la consulta de SQL siguiente:


sql = ( Espaís ELECTO_id,
variedad_agg(id) ' 'DE res_socio '
'DONDE Activo=cierto Y país_id NO ES NULL '
'GRUPO POR counprobar_id')

4. Ejecutar la consulta:
self.env.cr.Ejecuta(sql)

5. Itera sobre los resultados de la consulta para poblar el diccionario de resultado:


Modelo_de país = self.env[ Ess.País']
resultado = {}
Para país_id, socio_ids en self.env.cr.fetchall(): País =
country_modelo.Explora(país_id) socios =
self.Búsqueda(
[('id', 'en', tuple(socio_ids))]
)
Resultado[país] =
resultado de regreso de los
socios
131
Desarrollo de Lado de Servidor adelantado Técnicas

Cómo trabaja…
En paso 3, declaramos un SQL SELECCIONA query. Utiliza el id campo y el país_id
llave extranjera, el cual refiere al res_mesa de país. Utilizamos un GRUPO POR
declaración de modo que la base de datos la agrupación por país_id para nosotros, y la
variedad_agg función de agregación. Esto es un muy útil PostgreSQL extensión a SQL que
pone todos los valores para el grupo en una variedad, el cual mapas de Pitón a una lista.
Paso 4 llamadas el ejecutar() método en el cursor de base de datos almacenado en
self.env.cr. Esto envía la consulta a PostgreSQL y lo ejecuta.

Paso 5 usos el fetchall() método del cursor para recuperar una lista de filas seleccionó
por la consulta. De la forma de la consulta ejecutamos, sabemos que cada fila haber
exactamente dos valores, el primer país de ser_id y el otro un, la lista de ids para los
socios habiendo that país. Nosotros bucle sobre estas filas y crear recordsets de los
valores, el cual almacenamos en el diccionario de resultado.

Allí ha más…
El objeto en self.env.cr es un delgado wrapper alrededor de un psycopg2 cursor.
Los métodos siguientes son los querrás nose la mayoría del tiempo:
fEjecuta(consulta, params): Esto ejecuta la consultade SQLcon los
parámetrosmarcados como %s en la consulta sustituida con los valores en params,
el cual es un tuple

Aviso: nunca hacer la sustitución tú, cuando esto puede hacer el


código vulnerable a inyecciones de SQL.

ffetchone(): Esto regresa uno rema de la base de datos, envuelto en un tuple


(incluso sihay sólo una columna seleccionada por la consulta)
f fetchall(): Esto regresa todas las filas de la base de datos como lista de tuples
ffetchalldict(): Esto regresa todas las filas de la base de datos como
listanombres de columna de mapeo de diccionarios a valores
Ser muy prudente cuándo tratando consultas de SQL crudo:

fEresbypassing toda la seguridad de la aplicación. Ser seguro para


llamarbúsqueda([('id', 'en', tuple(ids)]) con cualquier lista de ids
estás recuperando para filtrar fuera de registros al cual el usuario no tiene ningún
acceso a.
fCualquiermodificación estás haciendo es bypassing los constreñimientos puestos
por el addonmódulos, excepto el NO NULL, UNIQUE, y constreñimientos CLAVES
EXTRANJEROS, which está aplicado en el nivel de base de datos. Así que es
cualquier campo computado recomputation gatillos, así que puedes acabar
corromper la base de datos.
132
Capítulo 6

Ve también
f Para administración de derechos del acceso, ve Capítulo 10, Seguridad de Acceso.

Escribir un brujo para guiar el usuario


En el Uso Modelos Abstractos para receta de características de Modelo reutilizable en
Capítulo 4, Modelos de Aplicación, los modelos de clase de la base.TransientModel
Estuvo introducido; estas participaciones de clase mucho con los modelos normales
exceptúan que los registros de modelos transitorios son periódicamente limpiados arriba en
la base de datos, por ello el nombre transitorio. Estos suelen crear brujos o cajas de diálogo,
los cuales están rellenados la interfaz de usuario por los usuarios y generalmente utilizados
para actuar acciones en los registros persistentes de la base de datos.
Esta receta extiende el código de Capítulo 3, Creando Odoo Módulos, por crear un brujo
para grabar el tomando prestado de libros por un miembro de biblioteca.

Preparándose
Si quieres seguir la receta, marca seguro tienes el mi_módulo addon módulo de
Capítulo 3, Creating Odoo Módulos.

También utilizaremos un modelo sencillo a préstamos de libro récord:

Clase
LibraryBookLoan(modelos.Modelo):
_nombre =
'biblioteca.Libro.Préstamo'
Libro_id = campos.Muchos2un('biblioteca.Libro',
'Libro',
requerido=Cierto)
Miembro_id = campos.Muchos2un('biblioteca.Miembro',
'Borrower',
requerido=Cierto)
Campos = estatales.Selección([('actual',
'Actual'), ('hecho',
Hecho')], estate',
default='Actual', requerido=Cierto)

Cómo para hacerlo…


Para añadir un brujo para grabar tomó prestado libros al addon módulo, necesitas actuar
el paso siguientes:
1. Añadir un modelo transitorio nuevo al módulo con la definición siguiente:
Clase LibraryLoanWizard(modelos.TransientModel):
_Nombre = 'biblioteca.Préstamo.Brujo'
Miembro_id = campos.Muchos2un('biblioteca.Miembro',
soyrescoldo') reserva_ids =
campos.Muchos2muchos('biblioteca.Libro', 'Libros')

133
Desarrollo de Lado de Servidor adelantado
Técnicas

2. Añadir el callback el método que actúa la acción en el modelo transitorio. Añadir


el código siguiente al LibraryLoanWizard clase:
@api.multi
def
Préstamos_récord(se
lf): para brujo en
self:
member = Brujo.Miembro_id
reserva = brujo.Libro_ids
Préstamo =
self.env['Biblioteca.Libro.Préstamo']
para libro en brujo.Libro_ids:
Préstamo.Crea({ soyrescoldo_id':
member.id, 'libro_id':
book.id})

3. Crear una vista de forma para el modelo. Añadir la definición de vista siguiente al módulo
views:
<Récord id='forma_de brujo_de préstamo_de biblioteca'
modelo='ir.ui.Vista'> <nombre de campo='nombre'>forma de
brujo de préstamo de biblioteca nombre</de campo> <de campo
de vista= soyodel'>biblioteca.Préstamo.Campo</de brujo>
<Nombre de campo='arco'
tipo='xml'> <cuerda de
forma="Toma prestado libros">
<Hoja>
<Grupo>
<Campo name=
soyrescoldo_id'/> </grupo>
<Grupo>
<Nombre de
campo='libro_ids'/>
</grupo>
<Hoja>
<footer>
<Nombre de botón= es cordón_presta'
Cuerda='VALE'
clase='btn-
'tipo'primarioobjet
o'/>
O
<Cuerda de botón='Cancelar'
clase='btn-default'
especial='cancelar'
/>
</footer>
</Forma>
</Campo>
</Récord>

4. Crear una acción y una entrada de carta para mostrar el brujo. Añadir el
siguiente declarations al archivo de carta del módulo:
<Ventana_de acto id="libros_de préstamo_de
brujo_de acción"
nombran="Préstamos Récord"

134
Capítulo 6
res_Biblioteca="de modelo.Préstamo.Brujo"
view_Objetivo="d
e forma" del
modo="nuevo"
/>
<menuitem id="Libros_de préstamo_de brujo_de
carta" carta="de libro_de
biblioteca_de padre" préstamo="de
brujo_de acción_de
acción_secuencia" de libros="20"
/>

Cómo trabaja…
Paso 1 define un modelo nuevo. Es no diferente de otros modelos, aparte de la clase de
base, el cual es TransientModel en vez de Modelo . Ambos TransientModel y el
modelo comparte una clase de base común llamó BaseModel, y si compruebas el
código de fuente de Odoo, verás que 99 por ciento del trabajo es en BaseModel y que
ambos Modelo y TransientModel es casi vacío.

Las cosas únicas que cambio para TransientModel los registros son como sigue:
fLos registros son periódicamente sacados de la base de datos así que las
mesas para los modelostransitorios no crecen arriba en medida con el
tiempo
fNo puedes definir reglas de acceso enTransientModels. Cualquiera está dejado
para crear unregistro, pero sólo el usuario quién creó un registro lo puede leer y
utilizarlo.
fNo tienes que definirUno2muchoscampos enTransientModelaquello
refiere a un modelonormal, cuando esto añadiría una columna en el modelo
persistente linrey a dato transitorio. Uso Muchos2muchas relaciones en este caso.
Naturalmente puedes definir Muchos2un y Uno2muchos campos para relaciones
entre modelos transitorios.
Definimos dos campos en el modelo, uno para almacenar el miembro que toma prestado los
libros y uno para almacenar la lista de ser de libros tomó prestado. Podríamos añadir otros
campos escalares para grabar una fecha de regreso planificada, para caso.
Paso 2 añade el código a la clase de brujo que se apellidará cuándo el botón definido en paso
3 es clicked encima. Este código lee los valores del brujo y crea
biblioteca.Libro.Registros de préstamo para cada libro.

Paso 3 define una vista para nuestro brujo. Complacer referir al Documento-receta de formas
del estilo en
Capítulo 8, Backend Vistas, para detalles. El punto importante aquí es el botón en el footer:
el atributo de tipo está puesto a 'objeto' , el cual significa que cuándo los clics de usuario en
el botón, el método con el nombre especificado por el atributo de nombre del botón se
apellidará.
135
Desarrollo de Lado de Servidor adelantado Técnicas

Paso 4 marcas seguro nosotros have un punto a favor de entrada nuestro brujo en la carta de la
aplicación. Utilizamos objetivo='nuevo' en la acción de modo que la vista de forma está
mostrada como caja de diálogo sobre la forma actual. Complacer referir al Añadir un Elemento
de Carta y receta de Acción de la Ventana en Capítulo 8,
Backend Vistas, para detalles.

Allí ha más…
Aquí es unos cuantos consejos para realzar vuestros brujos.

Utilizando el contexto para computar default valores


El brujo estamos presentando requiere el usuario para rellenar el nombre del miembro en
la forma. Hay una característica de la web client podemos utilizar para salvar algunos
escribiendo. Cuándo una acción está ejecutada, el contexto está actualizado con algunos
valora que puede ser utilizado por brujos:

Clave Valor
Esto es el nombre del modelo relacionó a la acción. Esto es
Modelo_activo generalmente el
Ser de modelo displayed encima pantalla.
Activo_id Esto indica que un registro solo es activo, y proporciona el ID de aquel
Récord.
Si varios registros estuvieron seleccionados, esto será una lista con el
Activo_ids IDs (esto
Pasa cuándo varios elementos están seleccionados en una vista de árbol
cuándo la acción
Está provocado. En una vista de forma, consigues [activo_id]).
Ámbito_activo Un ámbito adicional en qué el brujo operará.

Estos valores pueden soler computar default valores del modelo, o incluso directamente en el
método llamado por el botón. To Mejora en el ejemplo de receta, si tuvimos un botón mostrado
en la vista de forma de una biblioteca.Modelo de miembro para lanzar el brujo, entonces el
contexto de la creación del brujo contendría {'modelo_activo':
'biblioteca.Miembro', 'activo_id': <miembro id>}. En that caso, podrías definir el
miembro_id campo
Para tener un default el valor computado por el método siguiente:

def _default_Miembro(self):
Si self.Contexto.Consigue('modelo_activo') ==
'biblioteca.Miembro': regreso
self.Contexto.Consigue('activo_id', Falso)

Brujos y código reuse


En paso 2, podríamos haber dispensado con el para brujo en self bucle, y supuso
que len(self) es 1, posiblemente añadiendo una llamada a self.Asegura_un() a
principios del método, así:
@api.multi
def El registro_toma
prestado(self):
self.Asegura_un()

136
Capítulo 6
Miembro = self.Miembro_id
libros = self.Libro_ids
miembro.Toma
prestado_libros(libros)

Recomendamos utilizar la versión en la receta aun así, porque deja reusing el brujo de otras
partes del código por crear registros para el brujo, poniendot dobladillo en un solo recordset
(ve el Combinar recordsets receta en Capítulo 5, Desarrollo de Lado de Servidor Básico, para
ver cómo para hacer este) y entonces llamando préstamos_récord() en el recordset.
Concedido, aquí el código es trivial y tú no realmente necesidad de saltar a través de unll
aquellos hoops para grabar que algunos libros estuvieron tomados prestado por miembros
diferentes. Aun así, en un Odoo caso, algunas operaciones son mucho más complejas, y es
siempre bueno de tener un brujo disponible que hace "la cosa correcta." Cuándo utilizando
tales brujos, ser seguro para comprobar el código de fuente para cualquier uso posible del
modelo_activo / activo_id / activo_ids llaves del contexto, en qué caso,
necesitas pasar un contexto hecho de encargo (ve la Llamada un método con una receta de
contexto modificada anteriormente para cómo para hacer este).

Redirecting El usuario
El método en paso 2 no regresa cualquier cosa. Esto causará el diálogo de brujo para ser
cerrado después de la acción está actuada. Otra posibilidad es para tener el método regresa
un diccionario con los campos de un ir.Acción. En este caso, elw eb el cliente procesará la
acción como si una entrada de carta había sido clicked encima por el usuario. Para caso, si
quisimos mostrar la vista de forma del miembro quién ha justo tomó prestado los libros,
podríamos haber escrito el siguientes:
@api.multi
def El registro_toma
prestado(self): para
brujo en self:
Brujo = de
miembro.Miembro_id reserva
= brujo.Libro_ids
miembro.Toma
prestado_libros(libros)
Miembro_ids = self.mapped(
Soyrescoldo_id').ids Acción = {
'Tipo': 'ir.Acción.Ventana_de
acto', 'nombre': 'Prestatario',
ess_modelo':
'biblioteca.Miembro',
'Ámbito': [('id', '=', miembro_ids)],
'modo_de vista': 'forma,árbol',
}
Acción de regreso
Esto construye una lista de miembros quién ha tomado prestado reserva de este brujo (en
práctica, sólo habrá uno tal miembro, cuándo el brujo se apellida de la interfaz de usuario)
y crea un dynamic acción, el cual muestra los miembros con el especificados IDs.

137
Desarrollo de Lado de Servidor adelantado Técnicas

Este truco puede ser extendido por habiendo un brujo (con varios pasos para ser actuados uno
tras otro), o dependiendo de algún conditiencima de los pasos de preceder, por proporcionar un
botón Próximo que llamadas un método definido en el brujo. Este método actuará el paso (quizás
utilizando un campo escondido y almacenando el número de paso actual), actualización algunos
campos en el brujo, y regresar una acción then voluntad redisplay el mismo brujo actualizado y
prepararse para el paso próximo.

Define onchange métodos


Cuándo escribiendo Odoo modelos, es a menudo el caso que algunos campos están
interrelacionados. Hemos visto cómo para especificar constreñimientos entre campos en el
Añadir constraint validaciones a una receta de Modelo en Capítulo 4, Modelos de Aplicación.
Esta receta ilustra un concepto ligeramente diferente—onchange los métodos se apellidan
cuándo un campo está modificado en la interfaz de usuario para actualizar los valores de
otros campos del registro enel w eb cliente, normalmente en una vista de forma.
Ilustraremos esto por proporcionar un brujo similar al definido en la receta de preceder,
Escribir un brujo para guiar el usuario, pero cuáles pueden soler regresos de préstamo
récord. Cuándo el miembro está puesto en el brujo, la lista de libros está actualizada a los
libros actualmente tomados prestado por el miembro. Mientras estamos demostrando
onchange métodos en un TransientModel, estas características son también
disponibles en Modelos normales.

Preparándose
Si quieres seguir la receta, marca seguro tú have el mi_módulo addon de Capítulo 3,
Creando Odoo Módulos, con el Escribir un brujo para guiar los cambios de la receta de
usuario aplicaron.

También querrás preparar vuestro trabajo por definir el modelo transitorio


siguiente para el brujo:
Clase LibraryReturnsWizard(modelos.TransientModel):
_Nombre = 'biblioteca.Regresos.Brujo'
Miembro_id = campos.Muchos2un('biblioteca.Miembro',
soyrescoldo') reserva_ids =
campos.Muchos2muchos('biblioteca.Libro', 'Libros')
@api.multi
def Regresos_récord(self):
Préstamo =
self.env['Biblioteca.Libro.Préstamo'
] para rec ens elfo:
Préstamo = de préstamos.Búsqueda(
[( Estate', '=', 'actual'),
('libro_id', 'en',
rec.Libro_ids.ids), (
soyrescoldo_id', '=',
rec.member_id.id)]
)
Préstamos.Escribe({ estate': 'hecho'})

Finalmente, necesitarás definir una vista, una acción, y una entrada de carta para el
brujo. Esto queda como un ejercicio.
138
Capítulo 6

Cómo para hacerlo…


A automáticamente poblar la lista de libros para regresar cuándo el usuario está cambiado,
necesitas añadir un onchange método en el LibraryReturnsWizard paso con la definición
siguiente:
@api.onchange(
Soyrescoldo_id') def
onchange_miembro(self):
Préstamo =
self.env['Biblioteca.Libro.Préstamo'
] presta = préstamo.Búsqueda(
[( Estate', '=', 'actual'), (
soyrescoldo_id', '=',
self.member_id.id)]
)
self.Libro_ids = préstamos.mapped('Libro_id')

Cómo trabaja…
Un onchange usos de método the @api.onchange decorator, El cual está pasado los
nombres de los campos que cambio y así provocará la llamada al método. En nuestro
caso, decimos que siempre que miembro_id está modificado en la interfaz de usuario,
el método se tiene que apellidar.
En el cuerpo del method, buscamos los libros actualmente tomados prestado por el
miembro, y utilizamos una asignación de atributo para actualizar el libro_ids atributo
del brujo.

El @api.onchange decorator Cuida de modificar la vista envió al


cliente de web para añadir un encima_atributo de cambio al
campo. Esto utilizó para ser una operación manual en el "viejo API".

Allí ha más…
El uso básico de onchange los métodos es para computar valores nuevos para campos
cuándo algunos otros campos están cambiados en la interfaz de usuario, cuando
hemos visto en la receta.
Dentro del body del método, consigues acceso a los campos mostraron en la vista actual del
registro, pero no necesariamente todos los campos del modelo. Esto es porque onchange los
métodos se pueden apellidar mientras el registro está siendo creado en la interfaz de usuario
antes de que está almacenado en la base de datos! Dentro de un onchange método, self es
en un estado especial, denotado por el hecho que self.id no es un entero, pero un caso de
openerp.Modelos.NewId . Por tanto, no tienes que hacer cualesquier cambios a la base de datos
en un onchange método, becautiliza el usuario puede acabar cancelar la creación del registro, el
cual no rodaría atrás cualesquier cambios hicieron
Por el onchanges llamó durante la edición. Para comprobar para este, puedes utilizar
self.env.in_ onchange() y self.env.in_borrador() —los regresos anteriores Ciertos
si el contexto actual de ejecución es un onchange método y los regresos últimos Ciertos si
self no es todavía cometido a la base de datos.

139
Desarrollo de Lado de Servidor adelantado Técnicas

Además, onchange los métodos pueden regresar un diccionario de Pitón. Este diccionario
puede tener las llaves siguientes:
fAviso: El valor tiene que ser otro diccionario con el títulode llavesy
mensajerespectivamente conteniendo el título y el contenido de una caja de
diálogo, el cual será mostrado cuándo el onchange el método está corrido. Esto
somos eful para dibujar la atención del usuario a incongruencias o a problemas
potenciales.
fÁmbito: El valor tiene que ser otros nombres de campo de mapeo de diccionario a
ámbitos. Estoes útil cuándo quieres cambiar el ámbito de un Un2mucho campo
dependiendo de el valor de otro campo.
Para caso, supone tenemos un valor fijo puesto para fecha_de regreso_esperado
en nuestra biblioteca.Libro.Modelo de préstamo, y queremos mostrar un aviso
cuándo un miembro tiene algunos reserva aquello es tarde. También queremos restringir
la elección de libros a tél unos actualmente tomados prestado por el usuario. Podemos
reescribir el onchange método como sigue:
@api.onchange(
Soyrescoldo_id') def
onchange_miembro(self):
Préstamo =
self.env['Biblioteca.Libro.Préstamo'
] presta = préstamo.Búsqueda(
[( Estate', '=', 'actual'), (
soyrescoldo_id', '=',
self.member_id.id)]
)
self.Libro_ids =
préstamos.mapped('Libro_id') resultado
= {
'Ámbito': {'libro_ids': [
('id', 'en', self.Libro_ids.ids)]
}
}
Ámbito_tardío = [
('id', 'en', préstamos.ids),
('Fecha_de regreso_esperado', '<', campos.Fecha.Hoy())
]
Préstamos_de préstamos =
tardíos.Búsqueda(ámbito_tardío) si
préstamos_tardíos:
Mensaje = ('Advertir el miembro que el siguiente
' 'los libros son tarde:\n')
Títulos =
préstamos_tardíos.mapped('book_id.name')
Resultado['aviso'] = {
'Título': 'Tarde reserva',
Soyessage': mensaje + '\n'.Une(títulos)
}
Resultado de regreso

140
Capítulo 6

Llamada onchange métodos en el lado de


servidor
El Crear Actualización y registros nuevos valores de un recordset recetas récord en Capítulo
5, Desarrollo de Lado de Servidor Básico, mencionó que estas operaciones no llamaron
onchange métodos automáticamente. Yet En un número de casos es importante que estas
operaciones se apellidan porque actualizan campos importantes en el registro creado o
actualizado. Naturalmente, puedes hacer la computación requerida tú, pero esto no es
siempre posible como el onchange método cun ser añadido o modificado por un tercer-
partido addon el módulo instalado en el caso que no sabes aproximadamente.
Esta receta explica cómo para llamar el onchange métodos en un registro por
manualmente jugando el onchange método antes de crear un registro.

Preparándose
Nosotros reutilización los encuadres de la receta de preceder, Escribe onchange métodos.
La acción tendrá lugar en un método nuevo de biblioteca.El miembro llamó
regresar_todos los _libros(self).

Cómo para hacerlo…


En esta receta, manualmente crearemos un registro de la biblioteca.returns.Modelo
de brujo, y queremos el onchange método para computar el regresó libros para nosotros.
Para hacer este, necesitas actuar los pasos siguientes:
1. Crear el método regresa_todos los _libros en el LibraryMember clase:
@api.multi
def Regresa_todos los
_libros(self):
self.enseguro_uno

2. Conseguir un vacío recordset para biblioteca.Regresos.Brujo:


Brujo = self.env['Biblioteca.Regresos.Brujo']

3. Preparar los valores para crear un registro de brujo nuevo:


Los valores = { soy rescoldo_id': self.id,
libro_ids=Falso}

4. Recuperar el onchange especificaciones para el brujo:


specs = Brujo._onchange_spec()

5. Conseguir el resultado del onchange método:


Brujo = de actualizaciones.onchange(Valores, [
soyrescoldo_id'], specs)
6. Fusionar estos resultados con los valores del brujo nuevo:
Actualizaciones = de
valor.Consigue('valor', {}) para
nombre, val en valor.iteritems():

141
Desarrollo de Lado de Servidor adelantado Técnicas

Si isinstance(val, tuple):
valor[nombre] = val[0]
Valores.Actualización(valor)

7. Crear el brujo:
Brujo = récord.Crea(valores)

Cómo trabaja…
Para una explicación de paso 1 para dar un paso 3, complacer referir a la receta Crea
registros nuevos en
Capítulo 5, Desarrollo de Lado de Servidor Básico.

Paso 4 llamadas el _onchange_spec método en el modelo, pasando ningún argumento.


Este método recuperará las actualizaciones que está provocado por la modificación del cual
otsu campo. Él esto por examinar la vista de forma del modelo (recuerda, onchange los
métodos son normalmente llamados por el cliente de web).

Paso 5 llamadas el onchange(valores, nombre_de campo, campo_onchange)


método del modelo con 3 argumentos:
fValores: La lista de valores queremos puestos en el registro. Necesitas
proporcionar un valorpara todos los campos esperas ser modificado por el
onchange método. En la receta, ponemos libro_ids a Falso por esta razón.
fNombre_de campo: Una lista de campos para qué queremos gatillo the onchange
métodos.Puedes pasar una lista vacía, y utilice los campos definieron en valores.
Aun así, a menudo querrás especificar aquella lista manualmente para controlar el
orden de evaluación, en caso los campos diferentes pueden actualizar un campo
común.
fCampo_onchange: El onchange especificaciones que estuvo computado en paso
4. Estemétodo descubre qué onchange los métodos se tienen que apellidar y en
qué orden y regresa un diccionario, los cuales pueden contener las llaves
siguientes:
‰‰ Valor: Esto es un diccionario de nuevamente computado field valores.
Este diccionario sólo presenta llaves que es en el parámetro de
valores pasó a onchange() . Nota que Muchos2un campos son mapped
a un tuple conteniendo (id, nombre_de exhibición) como una
optimización para el cliente de web.
‰‰ Aviso: Esto es un diccionario containing un mensaje de aviso que el
cliente de web mostrará al usuario.
‰‰ Ámbito: Esto es unos nombres de campo de mapeo de diccionario a ámbitos

de validez nueva.

Generalmente, cuándo manualmente jugando onchange métodos, nosotros sólo cuidado


sobre qué es en valor.
142
Capítulo 6

Paso 6 actualizaciones nuestro diccionario de valores inicial con los valores computó por el
onchange. Procesamos los valores que corresponden a Muchos2un campos a sólo mantener
el id. Para hacer tan, aprovechamos el hecho que estos campos son sólo aquellos cuyo valor
está regresado como tuple.

Paso 7 finalmente crea el registro.

Allí ha más…
Si necesitas llamar un onchange método después de modificar un campo, el código es
igual. Justo necesitas conseguir un diccionario para los valores del registro, los cuales
pueden ser obtenidos by utilizando valores = dict(récord._cache) Después de
modificar el campo.

Ve también
fElCrear Actualización y registrosnuevos valores de recordset recetasde
registros enCapítulo 5,Desarrollo de Lado de Servidor Básico

Portuario viejo API código al nuevo API


Odoo Tiene una historia larga y el tan-llamado "tradicional" o "viejo" API ha sido en uso para
un tiempo muy largo. Cuándo diseñando el "nuevo" API en Odoo 8.0, el tiempo estuvo
tomado para asegurar que el APIs sería capaz de convivir, porque esté previsto que porting
el enorme codebase al nuevo API sería un esfuerzo enorme. Así que probablemente
encontrarás addon los módulos que utilizan el tradicionales API. Cuándo emigrándoles a la
versión actual de Odoo, puedes querer portuario les al nuevo API.
Esta receta explica cómo para actuar esta traducción. Pueda unlso servir como un asesor
memoire cuándo necesitas extender un módulo que usos el tradicionales API con el nuevos
API.

Preparándose
Dejado portuario el siguiente addon código de módulo desarrollado con el tradicional API:

De datetime fecha de importación,


timedelta de openerp.osv Importación
orm, campos
De openerp.Importación de herramientas _, DEFAULT_FORMATO_de FECHA_del
SERVIDOR cuando FECHA_FMT

Libro de biblioteca_de la
clase(orm.Modelo): _nombre
= 'biblioteca.Libro'
_columnas = {
'Nombre': campos.char('Nombre', requerido=Cierto),

143
Desarrollo de Lado de Servidor adelantado
Techniques

'Autor_ids': campo.Muchos2muchos( ess.Socio'),


}

Miembro de biblioteca_de la
clase(orm.Modelo): _nombre =
'biblioteca.Miembro'
_Hereda = { ess.Socio': 'socio_id'}

_Columnas = {
'Socio_id': campos.Muchos2un( ess.Socio',
'Socio',
requerido=Cier
to),
'Préstamo_duration': campos.Entero('duración de
Préstamo',
requerido=Cierto
),
'Inicio_de fecha': campos.Fecha( soyrescoldo
desde entonces'), 'fin_de fecha':
campos.Fecha('fecha de Expiración'), 'número':
campos.char('Número', requerido=Cierto),
}

_defaults = {
'Duración_de
préstamo': 10,
}

def Encima_fecha_de cambio_end(self, cr, uid, fin_de fecha,


contexto=Ninguno): fecha_de fin = de la fecha.strptime(Fin_de
fecha, FECHA_FMT)
Hoy = fecha.Hoy() si
fin_de fecha <= hoy:
Regreso {
'Valor': {'duración_de
préstamo': 0}, 'aviso': {
'Título': 'afiliación expirada',
soyessage': "Este miembro' afiliación " \
"Ha expirado",
},
}

def Toma prestado_libros(self, cr, uid, ids, libro_ids,


contexto=Ninguno): si len(ids) != 1:
Levanta orm.Excepto_orm(

_('Error!'),

_(' Está prohibido para prestar los mismos


libros ' 'a miembros múltiples.'))
Préstamo_obj = self.Piscina['biblioteca.Libro.Préstamo']
mRescoldo = self.Explora(cr, uid, ids[0], contexto=de
contexto) para libro_id en libro_ids:

144
Capítulo 6
val = self._Prepara_préstamo(
cr, uid, miembro, libro_id, contexto=de contexto
)
Préstamo_id = préstamo_obj.Crea(cr,
uid, val, contexto=de contexto)

def _Prepara_préstamo(self, cr,


uid, miembro,
libro_id,
contexto=Ninguno
):
Regreso {'libro_id': libro_id,
soyrescoldo_id': member.id,
'duración': miembro.Duración_de
préstamo}

Préstamo de libro_de biblioteca_de


clase(orm.Modelo): _nombre =
'biblioteca.Libro.Préstamo'

def _Computa_la fecha_prevista(self, cr, uid,


ids, campos, arg,
context=Ninguno):
res = {}
Para préstamo en self.Explora(cr, uid, ids, contexto=de
contexto): fecha_de fecha = del
inicio.strptime(Préstamo.Fecha, FECHA_FMT) fecha_de
inicio = de fecha_prevista + timedelta(préstamo=de
días.Duración) res[loan.id] =
fecha_prevista.strftime(FECHA_FMT)
Regreso res

_Columnas = {
'Libro_id': campos.Muchos2un('biblioteca.Libro',
requerido=Cierto), soyrescoldo_id':
campos.Muchos2un('biblioteca.Miembro',
Requerido=Cierto),
estate': campos.Selección([('actual', 'Actual'),
('Hecho', 'Hecho')],
estate',
requerido=Cierto),
'Fecha': campos.Fecha('fecha de Préstamo',
requerido=Cierto), 'duración':
campos.Entero('Duración'), 'la fecha_prevista':
campos.Función(
fnct=_Computa_la
fecha_prevista,
tipo='fecha', la
tienda=Cierta,

Cuerda='Previsto para'),
}

def _default_Fecha(self, cr, uid, contexto=Ninguno):

145
Desarrollo de Lado de Servidor adelantado Técnicas
retFecha de urna.Hoy().strftime(FECHA_FMT)

_defaults = { 'Duración':
15, 'fecha':
_default_fecha,
}

El módulo, naturalmente, definido algunas vistas. La mayoría de ellos necesitará ningún


cambio, así que no les mostraremos. El único uno pertinente en esta receta es la biblioteca
.Miembro param vista. Aquí es el pertinente excerpt para aquella vista:
<Récord id='biblioteca.Vista_de forma_del miembro'
modelo='ir.ui.Vista'> <nombre de campo=
soyodel'>biblioteca.Campo</de miembro>
<Nombre de campo='arco'
tipo='xml'> <!-- [...] -->
<Nombre de campo='fin_de fecha'
encima_cambia='encima_fin_de fecha_del
cambio(date_fin)'/>
<!-- [...] --
> </Campo>
</Récord>

Cómo para hacerlo…


A portuario este código de módulo al nuevo API, necesitas actuar los pasos siguientes:

1. Copia el archivo de fuente original para hacer una copia de seguridad.


2. En el archivo nuevo, modificar las importaciones de módulo como sigue:
De datetime fecha de importación, timedelta
De openerp modelos de importación, campos, api,
excepciones de openerp.Importación de herramientas
_

3. Modificar las definiciones de clase al nuevos API clases de base, y rebautizar las
clases para utilizar CamelCase:
Clase LibraryBook(modelos.Modelo):
_nombre = 'biblioteca.Libro'

Clase
LibraryMember(modelos.Modelo)
: _nombre =
'biblioteca.Miembro'
_Hereda = { ess.Socio': 'socio_id'}
Clase LibraryBookLoan(modelos.Modelo):
_nombre =
'biblioteca.Libro.Préstamo'

146
Capítulo 6

4. Emigrar las _definiciones de columnas a attribute declaration de campos en el


LibraryBook Clase:
‰‰ Las _llaves de columnas devienen la clase
‰‰
atribuye Los nombres de los tipos de campo
consiguen capitalizados
Clase
LibraryBook(modelos.Modelo):
_nombre = 'biblioteca.Libro'

Campos = de nombre.Char('Nombre',
requerido=Cierto) autor_ids =
campo.Muchos2muchos( ess.Socio')

No olvida para sacar las comas en los fines de las líneas.

5. Hacer la misma cosa para LibraryMember, cuidando para mover


_defaults declarations a la definición de campo:
Clase LibraryMember(modelos.Modelo):
# [...]

partner_id = Campos.Muchos2un( ess.Socio',


'Socio',
requerido=Cier
to)
Campos_de duración = del préstamo.Entero('duración de
Préstamo',
default=10,
Requerido=Cier
to) campos_de inicio = de la fecha.Fecha(
soyrescoldo desde entonces') campos_de fin = de
la fecha.Fecha('fecha de Expiración') campos =
de número.Char('Número', requerido=Cierto)

6. Emigrar la definición de la columna del LibraryBookLoan clase, cambiando el tipo


del campo de función a campos.Fecha :
Clase LibraryBookLoan(modelos.Modelo):
# [...]

Libro_id = campos.Muchos2un('biblioteca.Libro',
requerido=Cierto) miembro_id =
campos.Muchos2un('biblioteca.Miembro',
Requerido=Cierto)
Campos = estatales.Selección([('actual', 'Actual'),
('hecho', 'Hecho')],
estate',
requerido=Cierto)
Campos = de fecha.Fecha('fecha de Préstamo',
requerido=Cierto,
default=_default_fecha)

147
Desarrollo de Lado de Servidor adelantado
Techniques

Campos = de duración.Entero('Duración', default=15)


Fecha_campos = previstos.Fecha(

computa='_computar_la fecha_prevista',

La
tienda=Cierta,
cuerda='Previsto
para'
)

7. En el LibraryBookLoan clase, emigrar la definición del


_computar_fecha_función prevista al nuevo API:
Sacar todos los argumentos excepto
‰‰

‰‰ self Añadir un @api.Depende


‰‰ decorator
Cambio el cuerpo del método para utilizar el protocolo de campo computado
nuevo (ve el Añadir computó campos a una receta de Modelo en Capítulo 4,
Modelos de Aplicación, para detalles):
# En clase LibraryBookLoan @api.Depende(
esfecha_de tart', 'fecha_prevista') def
_computar_la fecha_prevista(self):
Para préstamo en self:
Campos_de fecha = del
inicio.Fecha.De_cuerda(préstamo.Fecha) fecha_de inicio =
de fecha_prevista + timedelta(préstamo=de días.Duración)
préstamo.La fecha_prevista =
fields.date.to_cuerda(fecha_prevista)

8. Yon el LibraryBookLoan clase, emigrar la definición del _default_función


de fecha:
‰‰ La definición de función tiene que ser movida antes del campo declaration
‰‰ El prototipo nuevo sólo tiene un argumento, self (ve el Añadir campos de
dato a una receta de Modelo en Ch más apto 4, Modelos de Aplicación,
para detalles):
# En clase LibraryBookLoan, antes de las definiciones de
campos def _default_fecha(self):
Campos de regreso.Fecha.Hoy()

9. Reescribir el tomar prestado_libros y _preparar_métodos de préstamo en el


LibraryMember clase:
‰‰ Añadir unn @api.multi decorator
‰‰ Sacar los argumentos cr, uid, ids, contexto
‰‰ Portuario el código al nuevo API (ve las varias recetas en este capítulo
para detalles)
‰‰ Reemplazar el orm.Excepto_orm excepción con UserError :
# En clase LibraryMember
@api.multi
def Toma prestado_libros(self, libro_ids):

148
Capítulo 6
Si len(self) != 1:
Levanta excepciones.UserError(
_(' Está prohibido para prestar los mismos
libros ' 'a miembros múltiples.')
)
Modelo_de préstamo = self.env['Biblioteca.Libro.Préstamo']
Para libro en
self.env['Biblioteca.Libro'].Explora(libro_ids): val
= self._Prepara_préstamo(libro)
Modelo = de préstamo_del
préstamo.Crea(val) @api.multi
def _Prepara_préstamo(self,
libro) self.Asegura_un()
Regreso {'libro_id': book.id,
soyrescoldo_id': self.id,
'duración': self.Duración_de
préstamo}

10. Portuario el encima_método_de fin_de fecha de cambio en el


LibraryMember clase:
‰‰ Añadir un @api.onchange decorator
‰‰ Portuario el código al nuevo API (ve el Escribir onchange receta de métodos
en este capítulo para detalles):
# En LibraryMember
@api.onchange('Fin_de
fecha')
def Encima_fin_de fecha_del cambio(self):
Campos_de fin = de la
fecha.Fecha.De_cuerda(self.Fin_de fecha) hoy =
fecha.Hoy()
Si fin_de fecha <= hoy:
self.Duración_de
préstamo = 0 regreso {
'Aviso': {
'Título': 'afiliación expirada',
soyessage': "la afiliación ha
expirado",
},
}

11. Editar la biblioteca.La definición de vista de forma de miembro unnd


sacar el encima_atributo de cambio en el campo_de fin de la fecha:
<Récord id='biblioteca.Vista_de forma_del miembro'
modelo='ir.ui.Vista'> <nombre de campo=
soyodel'>biblioteca.Campo</de miembro>
<Nombre de campo='arco'
tipo='xml'> <!-- [...] -->
<Nombre de campo='fin_de
fecha'/> <!-- [...] -->
</Campo>
</Récord>

149
Desarrollo de Lado de Servidor adelantado Técnicas

Cómo trabaja
Paso 1 cambios las importaciones. El viejo API vidas en el openerp.osv Paquete, el cual
cambiamos
Para utilizar openerp.Modelos, openerp.Campos, openerp.api, y openerp.Excepciones .
Nosotros altan gota la importación de DEFAULT_FORMATO_de FECHA_del SERVIDOR, porque
utilizaremos el helper métodos en campos.Fecha para actuar datetime / conversiones de
cuerda.

Paso 2 cambios las clases de base de los modelos. Dependiendo de la edad del código
estás emigrando, puedes need para reemplazar el siguiente:
f osv.osv, osv.Modelo u orm.Modelo con modelos.Modelo.
fosv.osv_Memoria,osv.TransientModel, o
orm.TransientModelCon modelos.TransientModel

Los atributos de clase habituales como _nombre, _orden, _hereda, _hereda, y tan en
are sin cambios.
Pasos 3 a 8 trata la migración de las definiciones del campo. El _campo de mapeo de
diccionarios de columnas nombres a definiciones de campo en el viejos API está emigrado a
atributos de clase.

Cuándo haciendo tan, no olvida para sacar las comas que siguen cada
definición de campo en el diccionario, otherwise el valor de atributo será un 1 -
elemento tuple, y conseguirás errores. También consigues una línea de
registro del aviso para estos.

Las clases de campo en openerp.Los campos normalmente tienen el mismo nombre


como su counterparts en openerp.osv.Campos, pero capitalizados
(openerp.osv.Campos.char Deviene openerp. Campos.Char). Default Los valores
están movidos del _defaults atributo de clase a un default parámetro en el tipo
declaration:
_Columnas = {
'Campo1': campos.char('Campo1'),
'campo2': campos.Entero('Campo2'),
}
_defaults = {
'Campo2': 42,
}

Ahora el código de preceder está modificado al siguiente:

Campo1 = campos.Char('Campo1')
Campo2 = campos.Entero('Campo2', default=42)
150
Capítulo 6

El cambio más grande es para functien campos. El viejo API campos de usos.La función
definida con un parámetro de tipo que da el tipo de la columna. El nuevo API utiliza un campo
del tipo esperado, definido con un computar parámetro, el cual da el método utilizó para
computar el campo:
_Columnas = {
'field3': campos.Función(

_computa_campo3, arg=Ninguno,

fnct_inv=_campo_de tienda3,

fnct_inv_arg=Ninguno, tipo='char',

fnct_campo=_de búsqueda_de la

búsqueda3, gatillo=de tienda_dict,

multi=palabra clave

),
}

Ahora el código de preceder está modificado al siguiente:

Campo3 = campos.Char('Field1'
computar='_computar_campo3
', inverse='_campo_de
tienda3',
búsqueda='_campo_de
búsqueda3', la
tienda=booleana)

El gatillo_dict en el viejo API está reemplazado con @api.Depende decorators, y no hay


ninguna necesidad para el multi parámetro en el nuevo API, cuando el computar
método can actualiza varios campos que comparten el mismo computar valor de parámetro.
Ver el Añadir Computó Campos a una receta de Modelo en Capítulo 4, Modelos de
Aplicación, para información más detallada.
Paso 9 emigra los métodos de lógica empresariales. El decorator para utilizar en el método
define las conversiones de parámetro, los cuales son para soler mapa los argumentos.
Necesitas escogerles cuidadosamente porque esto puede romper los módulos que utilizan
el viejos API extendiendo el ported módulo. El mismo consejo es válido si necesitas extender
un modelo nos definíing el viejo API con el nuevo API. Aquí es los casos más comunes, con
args <> denotando argumentos arbitrarios adicionales y argumentos de palabra clave:

Viejo API prototipo Nuevo API prototipo


def m(self, cr, uid, ids, <args>, @api.multi
Contexto=Ninguno) def m(self, <args>)
def m(self, cr, uid, <args>,
contexto=Ninguno) @api.Modelo
def m(self, <args>)
def m(self, cr, <args>) @api.cr
def m(self, <args>)

151
Desarrollo de Lado de Servidor adelantado Técnicas

Viejo API prototipo Nuevo API prototipo


def m(self, cr, uid, <args>) @api.cr_uid
def m(self, <args>)

Finalmente, da un paso 10 y 11 emigra el onchange método. Las cosas han cambiado


bastante un poco entre las dos versiones del API; en el tradicional API, onchange los
métodos están declarados en las definiciones de vista por utilizar un atributo
encima_cambio en <el elemento> de campo con un valor que describe la llamada para
ser actuada cuándo el campo está editado. En el nuevo API, este declaration no es
necesario porque el marco dinámicamente genera él en la vista por analizar el methods
decorado con @api.onchange .

152
7
Depuración y
Testaje
automatizado
En este capítulo, cubriremos los temas siguientes:

f Produciendo registros de servidor para ayudar


f depurar métodos Nosing el Odoo concha a
f interactivamente métodos de llamada
f Utilizando el depurador de Pitón para localizar ejecución de
método
f
Escribiendo pruebas para vuestro módulo que utiliza YAML
f
Escribiendo pruebas para vuestro módulo que
f
utiliza unidad de Pitón prueba Correr pruebas de
servidor
Utilizando el Odoo Comunidad Association maintainer
herramientas de calidad

Introducción
Vimos en Capítulo 5, Lado de Servidor Básico Lógica Empresarial, cómo para escribir
métodos de modelo para implementar la lógica de nuestro módulo. Aun así, un
desarrollador responsable no sólo escribe la implementación pero también proporciona
automated pruebas para esta implementación. Las recetas en este capítulo cubren la
depuración y probando de métodos de lado del servidor.
Produciendo registros de servidor
para ayudar depurar métodos
Registros de servidor son útiles cuándo intentando representar fuera qué ha sido pasando
en runtime before un accidente. También pueden ser añadidos para proporcionar
información adicional cuándo depurando un asunto. Estos espectáculos de receta cómo para
añadir logging a un método de existir.

153
Depuración y Testaje Automatizado

Preparándose
Añadiremos algunos logging declaraciones a tél siguiendo método, el cual salva los niveles
accionarios de productos a un archivo:
De os.Importación de camino une
De openerp modelos de importación, api,
las excepciones EXPORTA_DIR =
'/srv/exporta'

Clase
ProductProduct(modelos.Modelo):
_hereda = 'producto.Producto'
@api.Modelo
def Nivel_accionario_portuarioex(self,
ubicación_accionaria): productos =
self.Con_contexto(
Ubicación=stock_location.id ).Búsqueda([])

Productos = de
productos.Filtrado('qty_disponible') fname =
unir(EXPORTACIONES_DIR, estock_nivel.txt')
Prueba:
Con abierto(fname, 'w') cuando
fobj: para prod en
products:
fobj.Escribe('%s\t%f\n' % (prod.name,
prod.qty_Disponible
))
Excepto IOError:
Levanta excepciones.UserError('Incapaz de salvar
archivo')

Cómo para hacerlo…


Para conseguir algunos registros cuándo este método está siendo ejecutado, actuar los
pasos siguientes:

1. Enel beginnin g del código, importación el logging


módulo: importación logging

2. Antes de la definición de la clase de modelo, conseguir un logger para el módulo:


_logger = logging.getLogger(__Nombre__)

3. Modificar el código de la exportación_nivel_accionario() método como


sigue:
@api.Modelo
def Exporta_nivel_accionario(self,
ubicación_accionaria):
_logger.info('exportación nivel
accionario para %s',
stock_location.name)
Productos = self.Con_contexto(
Ubicación=stock_location.id).Búsqueda([])
productos = de
productos.Filtrado('qty_disponible')

154
Capítulo 7

_logger.Depura('%d productos en la
ubicación', len(productos))
fname = Une(EXPORTACIONES_DIR,
estock_nivel.txt') Prueba:
Con abierto(fname, 'w') cuando
fobj: para prod en
productos:
fobj.Escribe('%s\t%f\n' %
(prod.name,
prod.qty_Disponible))
Excepto IOError:
_logger.Excepción(
'Error mientras writing a %s en
%s', estock_nivel.txt',
EXPORTACIONES_DIR)
Levanta excepciones.UserError('Incapaz de
salvar
archivo')

Cómo trabaja…
Paso 1 importaciones el módulo logging de la Pitón biblioteca estándar. Odoo Utiliza este
módulo para dirigir sus registros.
Paso 2 instala un logger fo el módulo de Pitón. Utilizamos un modismo común en Odoo por
utilizar el __nombre__ variable automática para el logger nombre y llamando el logger
_logger.

La __variable__ de nombre está puesta automáticamente por el


intérprete de Pitón en tiempo de importación del módulo y su valor est él
nombre lleno del módulo. Desde Odoo hace un poco truco con las
importaciones, el addon los módulos están vistos por Pitón cuando
perteneciendo al openerp.addons Paquete de pitón. Tan si el código
de la receta es en mis_modelos/de módulo/book.py, __el
nombre__ será openerp.addons.my_Módulo.Modelos.Libro.

Por hacer este, conseguimos dos beneficios :

fEl global logging la configuración puesta enopenerplogger está aplicado a


nuestro logger,debido a la estructura jerárquica de loggers en el logging
módulo
fLos registros serán prefijados con el camino de módulo lleno, el cual es de gran
ayuda cuándo intentandoencontrar donde una línea de registro dada está
producida
155
Depuración y Testaje Automatizado

Paso 3 usos el logger para producir mensajes de registro. Métodos disponibles para este es
(por registro creciente level) depura, info, aviso, error, y crítico . Todos estos métodos
aceptan un mensaje en qué te puede tener % sustituciones y argumentos adicionales para
ser insertados en el mensaje. Tienes que no la % sustitución tú; el logging el módulo es
listo enough para actuar esta operación sólo si el registro tiene que ser producido. Si estás
corriendo con nivel de registro de INFO , entonces DEPURAR los registros evitarán hacer la
sustitución.

Otro método útil mostrado en la receta es _logger.Excepción(), los cuales pueden ser
utilizados en un exceptuarión handler. El mensaje será logged con un nivel de ERROR y el
stack el rastro es también imprimido en el registro de aplicación.

Allí ha más…
Puedes controlar el logging nivel de la aplicación de la línea de orden o del archivo
de configuración. Hay dos maneras principales de hacer este:
fPara controlar el nivel de registro globalmente, puedes utilizar el --registro-
opciónde línea de orden de nivel.Ve Capítulo 2, Dirigiendo Odoo Casos de
Servidor, para más información.
fPara poner el nivel de registro para un dado logger, puedes utilizar--registro-
handler=prefijo:nivel.En este caso, el prefijo es una pieza del camino del
logger nombre, y el nivel es uno
De DEPURAR , INFO, AVISO, ERROR, o CRÍTICO . Si omites prefijo, entonces
pusiste el default nivel para todo loggers. Para caso, para poner el logging nivel de
mi_mo dule loggers para DEPURAR y mantener el default nivel de registro para el
otro addons, puedes empezar Odoo así:
$ Pitón odoo.py --registro-handler=openerp.addons.my_módulo:DEPURA

f Es posible de especificar --registro-handler tiempo múltiple en la línea de orden.


f También puedes configurar el registro handler en el archivo de configuración de vuestro
Odoo caso.
En aquel caso, puedes utilizar una coma-lista separada de prefijo:pares de
nivel. Por ejemplo, la línea siguiente es un sane configuración para mínimo logging
producción, todavía manteniendot él mensajes más importantes: mantenemos
mensajes de error por default, excepto los mensajes produjeron por werkzeug
para qué sólo queremos mensajes críticos, y openerp.Servicio.Servidor para qué
mantenemos info mensajes de nivel (esto incluye la notificación de servidor start
arriba):
Registro_handler =
:ERROR,werkzeug:CRÍTICO,openerp.Servicio.Servidor:INFO
156
Capítulo 7

Utilizando el Odoo concha a


interactivamente métodos de llamada
El Odoo interfaz de web está significada para usuarios de fin, a pesar de que el modo de
desarrollador unlocks un número de características potentes. Aun así, probando y depurando a
través de la interfaz de web no es la manera más fácil de hacer cosas, cuando necesitas a
manualmente preparar dato, navigate en las cartas
Para actuar acciones, y tan encima. El Odoo la concha es una orden -interfaz de línea,
which te puede utilizar para emitir llamadas. Estos espectáculos de receta cómo para
empezar el Odoo concha y actuar acciones como llamar un método dentro de la concha.

Preparándose
Nosotros reutilización el mismo código cuando en la receta anterior para producir registros
de servidor para ayudar depurar métodos; esto habilita el producto.Modelo de producto
para añadir un método nuevo. Suponemos que tienes un caso con el addon instalado
disponible. En la receta, esperamos que tienes un Odoo archivo de configuración para este
caso proyecto llamado.conf.

Cómo para hacerlo…


Para llamar la exportación_nivel_accionario() método del Odoo concha, necesitas
actuar los pasos siguientes:
1. Inicio el Odoo la concha que especifica vuestro archivo de configuración del proyecto:
$ odoo/odoo.py Concha -c proyecto.conf --Registro-error=de nivel

2. Control para mensajes de error, y leer el texto de información mostrado antes de la


orden de Pitón habitual-tachar puntual:
env: <openerp.api.Objeto de entorno en 0x7fbc244e3un90>
openerp: <Módulo 'openerp' de '/recetario/de
casa/odoo/openerp/__ init__.pyc'>
self: res.Usuarios(1,)
Pitón 2.7.9 (default, Mar 1 2015, 12:57:24)
[GCC 4.9.2] en linux2
Ayuda "de tipo", "copyright", "créditos" o "licencia" para
más información.
(Consola)
>>>

3. Conseguir un recordset para producto.Producto:


>>> Producto = env['producto.Producto']
157
Depuración y Automatizado Testing

4. Conseguir el registro de ubicación accionario principal:


>>> Stock_de ubicación = env.ref('Producto.Stock_de
ubicación_accionaria')

5. Llamada la exportación_nivel_accionario() método:


>>> Producto.Exportación_nivel_accionario(stock_de ubicación)

6. Cometer la transacción antes de salir:


>>> env.cr.Comete()

7. Salida la concha por pulsar Ctrl+D.

Cómo trabaja…
Paso 1 usos odoo.py pelar para empezar el Odoo concha. Toda la orden habitual
argumentos de línea son disponibles. Utilizamos -c para especificar un archivo de
configuración del proyecto y --registro-nivelar para reducir la verbosidad de los registros.
Cuándo depurando, puedes querer tener un logging nivel de DEPURAR sólo para algún
concreto addons.
Antes de proporcionar tú con una orden de Pitón-tachar puntual, odoo.py la concha
empieza un Odoo caso que no escucha en la red e inicializa algunos variables globales, el
cual are mencionado en la producción:
fenvEs un entorno conectó a la base de datos especificada en la línea de orden o
en el archivo de configuración.
fopenerpEs elopenerpel paquete importado para ti. Consigues acceso a
todos los módulosde Pitón dentro de aquel paquete así que puedes hacer qué
quieres.
fselfEs un recordset de res.Los usuarios quecontienen un registro solo
para el Odoo super usuario(Administrador), el cual está enlazado al entorno env.
Paso 3 y 4 uso env para conseguir un vacío recordset y encontrar un registro por XML ID.
Paso 5 calls el método en el producto.Producto recordset. Estas operaciones son
idénticas a qué utilizarías dentro de un método, con la diferencia pequeña que utilizamos
env y no self. env (A pesar de que podríamos tener ambos tan son idénticos). Ve
Capítulo 5, Básico Server Desarrollo de Lado, para más información en qué es disponible.
Paso 6 comete la transacción de base de datos. Esto no es estrictamente necesario aquí
porque no modificamos cualquier registro en la base de datos, pero si habíamos hecho tan
y quiso estos cambios para persistir, esto es necesario—cuándo utilizas Odoo a través de
la interfaz de web,
Cada RPC carreras de llamada en su transacción de base de datos propia y Odoo dirige estos
para ti. Cuándo corriendo en el modo de concha, esto ya no pasa y tienes que llamar
env.cr.Comete() o env.cr.rollba ck() Tú. Otherwise, cuándo sales la concha, cualquier
transacción en progreso es automáticamente rodado atrás. Cuándo probando, esto es bien,
pero si utilizas la concha, por ejemplo, a guión la configuración de un caso, no olvida para
cometer vuestro trabajo!
158
Capítulo 7

Utilizando el depurador de Pitón para


localizar ejecución de método
A veces, registros de aplicación no son bastante para representar fuera de qué está yendo
incorrecto. Afortunadamente, tenemos el depurador de Pitón disponible a nosotros. Estos
espectáculos de receta cómo para insertar una rotura point en un método y localizar la
ejecución a mano.

Preparándose
Seremos reusing la exportación_nivel_accionario() el método mostrado en las dos recetas
anteriores. Ser seguro para tener una copia a mano.

Cómo para hacerlo…


Para localizar la ejecución de exportar_nivel_accionario( ) con pdb , seguir los pasos siguientes:

1. Editar el código del método, e insertar la línea destacó aquí:


def Exporta_nivel_accionario(self,
ubicación_accionaria): importación pdb;
pdb.Rastro_de conjunto()
Productos = self.Con_contexto(

ubicación=stock_location.id

).Búsqueda([])
fname = Une(EXPORTACIONES_DIR, estock_nivel.txt')
Prueba:
Con abierto(fname, 'w') cuando fobj:
Para prod en
productos.Filtrado('qty_disponible'):
fobj.Escribe('%s\t%f\n' % (
prod.name, prod.qty_Disponible))
Excepto IOError:
Levanta excepciones.UserError('Incapaz de salvar
archivo')

2. Corrido el método. Utilizaremos el Odoo concha, cuando explicado en el Uso el Odoo


concha a interactivamente receta de métodos de la llamada anteriormente:
$ odoo.py Concha -c proyecto.cfg --Registro-
error=de nivel [...]
>>> Producto = env['producto.Producto']
>>> Stock_de ubicación = env.ref('product.Stock_de
ubicación_accionaria')
>>> Producto.Exportación_nivel_accionario(stock_de ubicación)
> /Recetario/de
casa/nivel_accionario/models.py(16)exporta_nivel_accionario()
-> productos = self.Con_contexto(
(Pdb)

159
Depuración y Testaje Automatizado

3. En el (Pdb) puntual, asunto el args (atajo un) orden para conseguir los valores de
los argumentos pasaron al método:
(Pdb) Un
self = Producto.Producto() stock_de
ubicación = accionaria.Ubicación(12,)

4. Introducir la orden de lista para comprobar donde en el código estás estando:


(Pdb) Lista
def Exporta_nivel_accionario(self,
ubicación_accionaria): importación pdb;
pdb.Rastro_de conjunto()
Productos = self.Con_contexto(

ubicación=stock_location.id

).Búsqueda([])
fname = Une(EXPORTACIONES_DIR,
estock_nivel.txt') Prueba:
Con abierto(fname, 'w') cuando fobj:
Para prod en
productos.Filtrado('qty_disponible'):
fobj.Escribe('%s\t%f\n' % (prod.name,
prod.qty_Disponible))

5. Introducir la orden próxima tres tiempo para andar a través de las primeras líneas
del método. También puedes utilizar n, el cual es un atajo :
(Pdb) Luego
> /Recetario/de
casa/nivel_accionario/models.py(17)exporta_nivel_accionario()
->
Ubicación=stock_location.id
(Pdb) n
> /Recetario/de
casa/nivel_accionario/models.py(18)exporta_nivel_accionario()
-> ).Búsqueda([])
(Pdb) n
> /Recetario/de
casa/nivel_accionario/models.py(19)exporta_nivel_accionario()
-> fname = une(EXPORTACIONES_DIR, estock_nivel.txt')
(Pdb) n
> /Casa/cookbook/nivel_accionario/models.py(20)exporta_nivel_a
ccionario() -> probar:

6. Uso el p orden para mostrar los valores de los productos y fname variables:
(Pdb) p Productos
Producto.Producto(67, 14, 12, 6, 7, 8, 17, 18, 13, 55, 15, 10, 11,
64, 31, 23, 42, 30, 29, 53, 56, 63, 62, 43, 61, 35, 51, 26, 24, 25,
39, 40, 45, 34, 32, 33, 57, 65, 28, 27, 38, 16, 19, 49, 5, 36, 37,
44, 21, 22, 20, 59, 52, 66, 58, 54, 60, 46, 41, 47, 48, 50, 3,

160
Capítulo 7
2, 1, 4)
(Pdb) p fname
'/srv/Exporta/nivel_accionario.txt'

7. Cambio el value de fname para señalar al /tmp directorio:


(Pdb) !fname = '/tmp/Nivel_accionario.txt'

8. Uso el regreso (atajo r) orden para ejecutar la función actual a su fin:


(Pdb)
Regreso --
Regreso--
>
/Casa/afayolle/trabaja/OdooCookbook/proyecto1/nivel_accionario/mod
elos. py(22)exporta_nivel_accionario()->Ninguno
-> Para producto en productos.Filtrado('qty_disponible'):

9. Uso el cont (atajo c) orden a resume ejecución del programa:


(Pdb) c
>>>

Cómo trabaja…
En paso 1, nosotros hardcode un punto de rotura en el código de fuente del method
por llamar el rastro_de conjunto() método del pdb módulo de la Pitón
biblioteca estándar. Cuándo este método está ejecutado, el flujo normal de las
parones de programa, y consigues un (Pdb) incita en qué te puede introducir pdb
órdenes.

Paso 2 llamadas la exportación_de nivel_accionaria () el método que utiliza el modo de


concha. Es también posible de retomar el servidor normalmente y para utilizar la interfaz de
web para generar una llamada al método necesitas localizar por clicking en los elementos
apropiados de la interfaz de usuario.
Cuándo necesitas a manualmente step a través de algún código utilizando el depurador
de Pitón, aquí es unos cuantos consejos que hará vuestra vida más fácil:
fReduce el logging nivel para evitar habiendo demasiado registro tacha contaminar
la produccióndel depurador. Empezando en el nivel de ERROR es
generalmente bien. Puedes querer habilitar algunos concretos loggers con una
verbosidad más alta, el cual te puede hacer por utilizar el
--Registro-handler opción de línea de la orden (ve la receta de preceder,
registros de servidor del Producto para ayudar depurar métodos).
fCorrido el servidor con --trabajadores=0para evitar cualquier multiprocessing
emite que podríacausar el mismo punto de rotura para ser logrado dos veces en
dos procesos diferentes.
fCorrido
el servidor con --max-cron-hilos=0para inutilizar el procesamiento
de ir.cronTareas periódicas, el cual otherwise puede provocar mientras estás
dando un paso through el método, produciendo lado y registros indeseados efectos.

161
Depuración y Testaje Automatizado

Pasos 3 a 8 uso varios pdb órdenes para dar un paso a través de la ejecución del método. Aquí
es un resumen de las órdenes principales de pdb . La mayoría de ellos es también disponible
utilizando la primera letra como atajo. Indicamos esto por habiendo las letras opcionales entre
paréntesis:

f h(elp): Esto muestra ayuda en el pdb órdenes.


f Un(rgs): Esto muestra el valor de los argumentos de los métodos de función/actuales.
fl(ist): Esto muestra el código de fuente que es ejecutado por chunks de 11
líneas, inicialmentecentrados en la línea actual. Las llamadas sucesivas moverán
más allá en el archivo de código de la fuente. Opcionalmente, puedes pasar dos
enteros, inicio y fin , especificando la región
Para mostrar.
f p: Esto imprime una variable.
f pp: Esto bastante-impresiones una variable (útil con listas y diccionarios).
fw(Aquí): Esto muestra la llamada stack, con la línea actual en el inferior y
elintérprete de Pitón en la parte superior.
f u(p): Estos movimientos arriba de one nivel en la llamada stack.
f d(Propio): Esto mueve abajo uno nivela en la llamada stack.
fn(ext): Esto ejecuta la línea actual de código y entonces
parones.fs(tep): Esto es para dar un paso dentro de la
ejecución de una llamada de método.
f r(eturn): Esto resumes el executiencima del método actual hasta que regresa.
f c(ont): Esto resumes la ejecución del programa hasta el punto de rotura próximo está
pegado.
fb(reak) <args>: Esto crea un punto de rotura nuevo, y muestra su
identificador.argsPuede ser uno del siguiente:
‰‰ <Vacío>: Esto lista todos puntos de rotura
‰‰ Número_de línea: Estas roturas en la línea especificada en el archivo
‰‰
actual
filename:Número_de línea: Estas roturas en la línea especificada del
archivo especificado (cuál está buscado en los directorios de sys.Camino )
‰‰ function_Nombre: Estas roturas en la primera línea de la función
especificada

ftbreak <args>: Esto es similar de romperpero el punto de rotura será


cancelado después de queha sido logrado, ejecución tan sucesiva de la línea no
lo provocará dos veces.
f Inutiliza bp_id: Esto inutiliza un breakpoint por ID.
f Habilita bl_id: Esto habilita un discapacitado breakpoint por ID.
fj(ump) lineno: La línea próxima para ejecutar será el especificó. Esto puede
serpara reestrenar o a skip algunas líneas.
f(!) Declaración: Esto ejecuta un estado de Pitónment. El!El carácter puede
ser omitidosi la orden no parece un pdb orden; para caso, lo necesitas si quieres
poner el valor de una variable nombró un, porque un es el atajo para el args
orden.

162
Capítulo 7

Allí ha más…
En la receta, insertamos un pdb.Rastro_de conjunto() declaración para romper a pdb
. También podemos empezar pdb directamente de dentro del Odoo concha, el cual es muy
útil cuándo puedes no fácilmente modificar el código del proyecto por utilizar
pdb.runcall(). Esta función toma un method como el primer argumento y los argumentos
para pasar a la función como los argumentos próximos. Tan dentro del Odoo concha, tú
esto:
>>> Importación pdb
>>> Producto = env['producto.Producto']
>>> Stock_de ubicación = env.ref( Estock.Stock_de ubicación_accionaria')
>>> pdb.runcall(Producto.export_Nivel_accionario, stock_de
ubicación) > /recetario/de
casa/odoo/openerp/api.py(235)wrapper()
-> Si '_ids' en self.__dict__:
(Pdb)

Aviso que en este caso no acabas en la exportación_nivel_accionario() método


pero en el wrapper() función de openerp.api . Esto esp arte de la implementación del
@api.Modelo decorator pusimos en nivel_accionario_experto() y encontrarás
mucho estos en vuestro pdb sesiones cuándo dando un paso llamadas de método del
interior. Puedes tampoco manualmente paseo a través del decorators o añadir breakpoints
dentro del código de fuente de los métodos.
Si escoges dar un paso manualmente, necesitarás utilizar luego hasta que te la línea que
llama nuevo_api() y paso dentro de aquella llamada:
(Pdb) n
> /Recetario/de
casa/odoo/openerp/api.py(236)wrapper() -> regresar
nuevo_api(self, *args, **kwargs)
(Pdb) s
--
Llamada-
-
> /Recetario/de
casa/nivel_accionario/models.py(13)exporta_nivel_accionario()
-> @api.Modelo
(Pdb) n
> /Recetario/de
casa/nivel_accionario/models.py(15)exporta_nivel_accionario()
-> productos = self.Con_contexto(
Si bastante añadirías un breakpoint, control el nombre de archivo y número de línea y
utilizar la orden de rotura así:
(Pdb) b /Recetario/de
casa/nivel_accionario/models.py:15 Breakpoint 1 en
/recetario/de casa/nivel_accionario/models.py:15 (Pdb)
cont

163
Depuración y Testaje Automatizado

> /Recetario/de
casa/nivel_accionario/models.py(15)nivel_accionario_portuarioe
x() -> productos = self.Con_contexto(
(Pdb)

Aviso que tuvimos que utilizar el camino lleno al archivo porque no es en un


directorio dentro de sys.Camino .
En esta receta, centramos en el depurador de Pitón de la Pitón biblioteca estándar, pdb. Él is
muy útil de saber esta herramienta porque es guaranteed para ser disponible en cualquier
distribución de Pitón. Hay otros depuradores de Pitón disponibles, como ipdb
(https://pypi.
python.org/pypi/ipdb) Y pudb (https://pypi.python.org/pypi/pudb), los
cuales pueden ser utilizados tan gota-en sustituciones para pdb. Comparten el mismo API y
la mayoría manda visto en esta receta es unccolgado. Y, naturalmente, si desarrollas para
Odoo utilizando una Pitón IDE, ciertamente tienes acceso a un depurador integrado con él.

Ve también
f Para la documentación llena de pdb , refiere a https://d ocs.python.org/2.7/
Biblioteca/pdb.html

Escribiendo pruebas para vuestro módulo


que utiliza YAML
Odoo Apoya maneras diferentes de escribir addon pruebas de módulo, YAML pruebas, y
pruebas de Pitón. En esta receta, nosotros will ver cómo para escribir YAML pruebas para los
mis_métodos de módulo escribimos en
Capítulo 5, Desarrollo de Lado de Servidor Básico, en la receta Define métodos de Modelo
y utilizar el API decorators.

Preparándose
Esta receta supone tienes un caso a punto con el código parat él mi_módulo de módulo
definido en Capítulo 3, Creando Odoo Módulos, y el código del Definir métodos de Modelo y
utilizar el API decorators receta en Capítulo 5, Desarrollo de Lado de Servidor Básico.

Cómo para hacerlo…


Para escribir YAML pruebas de unidad para mi_módulo, necesitas seguir estos pasos:

1. Editar el __openerp__.py Archivo del módulo, y añadir la entrada de la prueba:


{ # …
'Prueba': ['libros/de prueba_de la prueba.yml']
}

164
Capítulo 7

2. Crear un directorio de prueba en


mi_módulo: $ mkdir prueba

3. Crear un archivo libros de prueba_llamada.yml En el directorio. Añadir una


descripción de prueba en la parte superior:
-
Prueba LibraryBook.Estado_de cambio

4. Añadir un paso que cambia el usuario actual al demo usuario:


-
!Contexto
uid: 'Base.Usuario_demo'

5. Añadir un paso de prueba que crea un libro:


-
Crea libro en redactar estatal
-
!reModelo {de cordón: biblioteca.Libro, id: testbook}:
- Nombre: Libro de Prueba
- Estatal: borrador

6. Añadir un paso que llama el cambio_método estatal:


-
Estado de cambio_de la llamada para hacer el libro disponible
-
!Modelo {de pitón: biblioteca.Libro, id:
testbook}: | self.Estado_de
cambio('disponible')

7. Añadir un paso que comprueba el resultado exitoso de la llamada:


-
!Afirma {modelo: biblioteca.Libro, id: testbook, cuerda:
estado incorrecto}:
- Estatal == 'disponible'

8. Añadir un paso que llama el cambio_método estatal con un estado prohibido:


-
Intenta llamar estado_de cambio para hacer borrador de libro
-
!Modelo {de pitón: biblioteca.Libro, id:
testbook}: | self.Estado_de
cambio('borrador')
165
Depuración y Testaje Automatizado
-
Control el libro es todavía disponible
-
!Afirma {modelo: biblioteca.Libro, id: testbook, cuerda:
estado incorrecto}:
- Estatal == 'disponible'

How Trabaja…
El YAML archivos estamos utilizando aquí es el mismo tan los utilizaron para cargar archivos
de dato
(Ve Capítulo 9, Dato de Módulo), exceptúa que están incluidos en la llave de prueba del
__openerp__.py Más que en la llave de dato. Añadimos que llave en paso 1. Son por tanto
procesados sólo cuándo corriendo las pruebas (ve el Servidor de Correr receta de Pruebas en
este capítulo).

Tradicionalmente, YAML las pruebas están añadidas al


subdirectorio/ de prueba del addon módulo, mientras
pruebas de unidad de la Pitón viven en el subdirectorio/
de pruebas.

Paso 3 añade una descripción en la parte superior del archivo de prueba en un YAML nodo
de prueba. Mente la sangría del texto, después del - delimitando un nodo. Esta descripción
será imprimida en el registro de prueba (en nivel de registro DEPURA).

Paso 4 usos un !Contexto YAML nodo para cambiar elev aluation el contexto utilizado en
la prueba.
El uso más común de este nodo es para modificar el usuario utilizó para correr la prueba del
administrador a alguien más por asignar una cuerda que contiene el XML ID del usuario a uid .

Es siempre práctica buena, cuándo writinpruebas de g, para tenerles corrido


con un usuario concreto, y de todas formas no con el administrador; este
usuario bypasses todos los controles de seguridad, así que esto esconderá
asuntos en vuestras reglas de seguridad.

Paso 5 crea algún dato de prueba utilizando un !Récord YAML nodo. El YAML attributes,
entre tirantes, dar el nombre del modelo para ser utilizado y el XML ID para utilizar para el
registro nuevo.

En todo el YAML archivos, para atención al espaciando, cuando la sintaxis es


bastante stringent; necesitas un espacio solo después de las comas, un solos
espaciales before el tirante de apertura, y el colon final tiene que ser justo
después del tirante de encierro.
Paso 6 usos un !Pitón YAML nodo para ejecutar algún código de Pitón. Los atributos
especifican el modelo para ser utilizado y el XML ID del registro. Dentro del bloque, self es
un conjuntorécord del modelo especificado que contiene un registro solo con el suministrado
XML ID.

166
Capítulo 7

YAML Sintaxis
Toma nota del | carácter al final del !Nodo de pitón. Suele denotar un
nodo de texto literal, en qué whitespace no es processed. Necesitas
esto para código de Pitón donde espaciando es significativo.

Dentro del bloque de Pitón, también puedes utilizar las variables siguientes:

fref: Esto es una función regresando un recordset de un XML ID pasado como


cuerdaftiempo: Esto es elmódulode tiempo de la Pitón biblioteca
estándar
fdatetime: Esto es eldatetimetipo deldatetimemódulo de la
Pitónbiblioteca estándar
ftimedelta: Esto es eltimedeltatipo deldatetimemódulo de la
Pitónbiblioteca estándar
En paso 7, utilizamos un !Afirma YAML nodo para hacer aserciones sobre el registro. Los
atributos especifican el modelo para utilizar y en qué XML ID las aserciones tienen que ser
comprobadas. El atributo de cuerda está utilizado en el mensaje de error si uno de los
controles en el nodo no es Cierto.
Ver el siguiente recipe, pruebas de servidor Corrido, para ver cómo para correr la prueba.

Allí ha más…
Cuando !Afirma no es conveniente para escribir controles, para caso, si no tienes un XML
ID para que así conste quieres control, puedes utilizar un !Bloque de pitón y el afirmar
palabra clave de Pitón. Nosotros could también reescribir el último control de la receta así:
-
Intenta llamar estado_de cambio para hacer borrador de libro,
control esto no tiene ningún efecto
-
!Modelo {de pitón: biblioteca.Libro, id:
testbook}: | self.Estado_de
cambio('borrador')
Afirma self.Estatal == 'disponible', 'incorrecto state %s' %
self.Estatal
167
Depuración y Testaje Automatizado

Escribiendo pruebas para vuestro módulo


que utiliza pruebas de unidad de la Pitón
YAML No es la manera única de escribir pruebas con Odoo. Si eres familiar con la unidad
de Pitón que prueba herramientas, serásp arrendado para saber que estos son también
disponibles dentro del Odoo marco. En esta receta, veremos cómo para escribir pruebas
de unidad de la Pitón para los mis_métodos de módulo escribimos en Capítulo 5,
Desarrollo de Lado de Servidor Básico, en la receta Define métodos de Modelo y uso the
API decorators.

Preparándose
Esta receta supone tienes un caso a punto con el código para el mi_módulo de módulo
definido en Capítulo 3, Creando Odoo Módulos, y el código de Capítulo 5, Desarrollo de Lado
de Servidor Básico, en la receta Define Modelo methods y utilizar el API decorators.

Cómo para hacerlo…


Para escribir pruebas de unidad para el módulo, actuar los pasos siguientes:

1. Crear un subdirectorio llamó pruebas dentro del addon directorio de


módulo: $mkdir mis_pruebas/de módulo

2. Crear un __init__.py Archivo en aquel directory con los contenidos


siguientes: de . Biblioteca de prueba_de la importación

3. Crear un test_library.py archivo en subdirectorio/ de pruebas.


Dentro de la prueba_ library.py archivo, importación el Odoo clase
de base de la prueba:
De openerp.Prueba.Importación común TransactionCase

4. Crear un TestCase class:


Clase LibraryTestCase(TransactionCase):

5. Añadir un setUp método que crea un libro:


def setUp(self):
super(LibraryTestCase, self).setUp()
Modelo_de libro =
self.env['Biblioteca.Libro'].sudo(
self.ref('Base.Usuario_demo')
)
self.Modelo = de libro_del libro.Crea(
168
Capítulo 7
{'Nombre': 'libro de
Prueba', estate':
'borrador',
}
)

6. Añadir un método de prueba que cambia el estado:


def Borrador_de cambio_de la prueba_disponible(self):
'''La prueba que cambia estado de redactar a
disponible''' self.Libro.Estado_de
cambio('disponible')
self.assertEqual(self.bovale.Estatal,
'disponible')

7. Añadir un segundo método de prueba intentando hacer un cambio estatal ilegal:


def Cambio_de prueba_borrador_disponible_ningún_efecto(self):
'''Prueba cambio estatal prohibido de disponible de
redactar''' self.Libro.Estado_de cambio('disponible')
self.Libro.Estado_de cambio('borrador')
self.assertEqual(
self.Libro.Estatal,
'Disponible',
'El estado no puede cambiar de disponible a %s' %
\ self.Libro.Estatal
)

Cómo trabaja…
Creamos una Pitón subpackage en nuestro módulo llamó pruebas y añadir un módulo
de prueba con un nombre que empieza con te st_. Esto es la convención utilizado por
Odoo para descubrimiento de prueba.
En este archivo, importamos la clase de prueba de la base, TransactionCase, de
openerp.Prueba.Común . Esta clase extiende el unittest.TestCase Clase de la Pitón
biblioteca estándar para hacer él propio para nosotrose en Odoo:
fElsetUp()el método inicializa elself.envAtributo, el cual te puede utilizar para
actuarlas operaciones habituales (ve las recetas en Capítulo 5, Desarrollo de Lado de
Servidor Básico)
fEltearDown()corros de método respaldan la transacción de base de datos de
modo que las pruebas estáncorridas en aislamiento

Si vuestro caso de prueba redefine estos dos métodos, ser


seguro para llamar el super() implementación.
169
Depuración y Testaje Automatizado

Las pruebas están definidas en los métodos nombraron con un prefijo de prueba. El
corredor de prueba correrá entonces uno tras otro con una llamada a setUp() antes de
cada método de prueba y una llamada a tearDown() después de que cada cual. Dentro
del método, puedes utilizar toda la aserción habitual métodos de unittest.TestCase . Aquí es
el más generalmente utilizó unos:

Método Controles que


assertEqual(Un, b) Un == b
assertNotEqual(Un, b) Un != b
assertTrue(x) bool(x) Es Cierto
assertFalse(x) bool(x) Es Falso
assertIn(Un, b) Un en b
assertNotIn(Un, b) Un no en b
Diversión(*args, **kwargs)
assertRaises(exc, diversión, levanta exc
*args, **kwargs)

Todos estos métodos excepto assertRaises() acepta un opcional msg argumento, el


cual será mostrado en el mensaje de error cuándo la aserción no es cierta. Otherwise, un
mensaje de error estándar está utilizado.
assertRaises Es más utilizado como director de contexto. Supone quieres probar que
modificando un registro levanta un UserError excepción. Puedes escribir la prueba
siguiente:
Clase TestCase(TransactionCase):
# setUp El método define self.Récord
def testWriteRaisesUserError(self):
Con self.assertRaises(UserError):
sElfo.Récord.Escribe({ esome_campo':
algún_valor})

La prueba tendrá éxito si la excepción pasó a assertRaises está generado por el bloque de
código; otherwise falle.
Para más información encima pruebas de unidad en Pitón, complacer referir a la biblioteca
estándar documentation en
https://docs.python.org/2.7/library/unittest.html#prueba-casos.

Nota que en el setUp() method, utilizamos sudo() para cambiar el usuario en el


entorno de self.Modelo_de libro . Esto asegura que las pruebas no correrán utilizando el
usuario de administrador, el cual bypasses las reglas de acceso y que las reglas de
seguridad instalamos en nuestro módulo está consiguiendo ejercitó.
Ver la receta siguiente, pruebas de servidor Corrido, para ver cómo para correr la prueba.
170
Capítulo 7

Allí ha más…
El módulo openerp.Prueba.Común define varias clases que puede ser utilizado tan
clases de base para casos de prueba:
fTransactionCase: Cada cual me pruebothod está corrido independientemente y la
transacciónde base de datos está rodada atrás después de que cada cual. Esto
significa que cualesquier cambios hicieron en uno prueba el método no es visto por
los otros métodos de prueba. Puedes utilizar el tradicional setUp() y tearDown()
métodos para actuar inicial de pruebaization y cleanup.
fSingleTransactionCase: Todos los métodos de pruebas están corridos en la
misma transacción,el cual es sólo rodado atrás después del último método. Si
necesitas actuar inicialización y cleanup para el caso de prueba, necesitas extender
el setUpClass() y tearDownClass() métodos. No olvida para decorar estos con
@classmethod , o conseguirás errores extraños cuándo llamando el super()
implementación.
fSavePointCase: Es una extensiónSingleTransactionCaseaquello
creauna base de datos SAVEPOINT antes de correr métodos de prueba y
restaurándoles después de que la prueba está corrida. El efecto neto es que puedes
correr vuestras pruebas en aislamiento cuando con TransactionCase sin teniendo
que pagar el precio de un costoso setUp() el método que recrea todo el dato entre
todas las pruebas—el initialization está actuado en setUpClass() y rodamos atrás
la transacción al estado salvado después de cada prueba.

El módulo también define dos decorators, en_instalar(bool) y el


correo_instala(bool). Por default, las pruebas para un dados addon el módulo está corrido
justo después del módulo está inicializado, antes de inicializar el próximo addon módulo; esto
corresponde a decorar los métodos de prueba con ambos @en_instalar(Cierto) y @el
correo_instala(Falso). A veces, puedes necesitar cambiar esto. Un caso típico es el
siguiente: módulo_un und módulo_b tanto extender el mismo modelo, pero no dependen de
uno otro. Ambos añaden un campo requerido al campo de modelo_un y campo_b y
proporcionar un default valor para aquel campo. En las pruebas de estos módulos, los registros
nuevos están creados. Si ambos módulos están instalados cuándo las pruebas está corrido,
Las pruebas fallarán, mientras que si módulo único_un o módulo_b está instalado, las
pruebas pasarán. La razón es que si, para caso, módulo_un está cargado primero, cuándo las
pruebas crean un registro nuevo el default valor para campo_b no es computado porque
módulo_b no es cargado todavía. Aun así, la base de datos NO NULL constreñimiento para
campo_b es presente e impedirá el registro de ser creó. Una solución es para decorar los
métodos de prueba de ambos módulos con
@En_instalar(Falso) y @p ost_instala(Cierto), el cual forzará las pruebas
para ser corridas después de todo los módulos han sido inicializados.
171
Depuración y Testaje Automatizado

Corriendo pruebas de servidor


Las dos recetas anteriores mostradas cómo para escribir pruebas. Dejado es ver cómo
para correrles! TSus trabajos de receta para ambos YAML y pruebas de unidad de la
Pitón.

Preparándose
Seremos reusing las pruebas para el mi_módulo de módulo de uno de las recetas
anteriores. Necesitarás un caso con el addon instalado. En esta receta, suponemos que el
caso configuration el archivo es en proyecto.cfg.

Cómo para hacerlo…


Para correr las pruebas para mi módulo addon, corrido la orden siguiente:

$ odoo/odoo.py -c Proyecto.cfg --Prueba-habilitar --registro-error=de


nivel --parón-después de que-init -u mi_módulo

Cómo trabaja…
La parte clave en este recipe es el --prueba-habilitar orden-bandera de línea que dice
Odoo para correr las pruebas. El --parón-después de que-init la bandera parará el
caso después de las pruebas ha corrido y -u actualizará el módulo especificado. Cuándo
una actualización (o instalar) está actuado en modo de prueba, todo el affected addon
módulos' las pruebas están corridas (esto incluye dependencias automáticamente
dependencias instaladas o inversas automáticamente actualizaron; ver la receta Instala y
upgrade local addon módulos en Capítulo 2, Dirigiendo Odoo Casos de Servidor, para más
información en este).

Cómo sabes que las pruebas corrieron exitosamente? El estado de salida de


Odoo Será igual al número de falló pruebas, así que si no es 0,
entonces al menos una prueba ha fallado. Conseguirás más
información sobre los fracasos en el registro de servidor messages.

Puedes correr las pruebas que utilizan la configuración de registro siguiente: --registro-
error=de nivel --registro-handler=openerp.Módulos.Cargando:INFO. Esto
deja para tener información sobre las varias pruebas' archivos para ser procesados pero
no los detalles de los registros del operationes, sólo los mensajes de error.

Allí ha más…
El principal drawback de de este modo de correr las pruebas es que tienes que correr todas
las pruebas para un dados addon módulo, incluso si sabes que ellos todos pasan pero el
estás intentando fijar, y también tienes que update el addon (cuáles pueden ser en él una
operación costosa).

172
Capítulo 7

Hay una manera alrededor de este. Si quieres correr las pruebas en


mi_prueba/de pruebas/del módulo_ library.py, puedes utilizar la orden
siguiente:
$ odoo/odoo.py -c Proyecto.cfg --Registro-nivel=error --parón-después de
que-init --prueba-archivar mis_pruebas/de módulo/test_library.py

Esto correrá sólo las pruebas definieron en aquel archivo, y trabaja también si especificas
un archivo que contiene YAML pruebas. Él también skip actualizando el módulo, así que
no trabaje si has changed la estructura de modelo por añadir campos nuevos o modificó
los archivos de dato del addon desde entonces la última vez el módulo estuvo actualizado.

Uno nota final sobre pruebas:


Siempre ser sospechoso si vuestras pruebas no son en error en la primera
carrera. Hay una posibilidad buena esto significa te equivocaste. Un típico
goof es para olvidar para añadir el YAML archivo de prueba en el
__openerp__.py Archivo, o para olvidar para importar el archivo de prueba
en pruebas/__init__.py. Es siempre una idea buena cuando
Las pruebas están pasando en la primera carrera para forzar un fracaso, for
caso, por añadir afirma Falso a la primera línea de un método y
corriéndoles otra vez.

Utilizando el Odoo Asociación


Comunitaria maintainer herramientas
de calidad
El Odoo Asociación Comunitaria (OCA) dirige un número grande de Odoo los proyectos que
utilizan el GitHub infrastructure. El uso de proyectos de la asociación Travis CI para
integración continua. Estos espectáculos de receta cómo puedes utilizar el maintainer QA
las herramientas desarrollaron por la comunidad en vuestro propio GitHub repositorios.

Preparándose
Para utilizar esta receta, necesitas tener un público GitHub repositorio con vuestros módulos. En
el tiempo de escribir, el OCA las herramientas esperan que este repositorio contiene varios
addons en subdirectorios.
173
Depuración y Testaje Automatizado

Cómo para hacerlo…


Para integrar el OCA maintainer-quality-herramientas con vuestro repositorio, necesitas
actuar los pasos siguientes:
1. Conecta a https://travis-ci.org/ .

2. Para firmar en, escoge Señal en con Github.

174
Chapter 7

3. Clic en vuestro nombre en la esquina correcta superior para acceder a los


encuadres de vuestro perfil, cuando mostrados en el siguientes screenshot:

4. Clic en el Sync botón para cargar la información aproximadamente todos vuestros


repositorios públicos en Travis. Esto puede tomar un par de los minutos que
dependen de cuántos repositorios tienes.
5. Para todos los repositorios quieres uso Travis encima, habilitarles por toggling la
cruz gris a una marca de control verde.
6. Puedes clic en el cogwheel para acceder cada repository encuadres, pero el
defaults es VALE también.

175
Depuración y Testaje Automatizado

7. Dentro de un clon local de vuestro repositorio, crear un archivo llamó


.travis.yml Con el contenido siguiente:
Lengua: pitón
sudo: Falso
cache:
Apto:
directorios
ciertos:
- $CASA/.cache/pip
Pitón:
- "2.7"
addons:
Apto:
Paquetes:
- Espera-dev # proporciona unbuffer utilidad
- Pitón-lxml # porque pip la instalación es lenta
- Pitón-simplejson
- Pitón-serial
- Pitón-yaml
virtualenv:
Paquetes_de sitio_del
sistema: cierto env:
Global:
- VERSION="9.0" PRUEBAS="0" CONTROL_de
PELUSA="0" matriz:
- CONTROL_de PELUSA="1"
- PRUEBAS="1" ODOO_REPO="odoo/odoo"
- PRUEBAS="1"
ODOO_REPO="OCA/OCB" instala:
- git Clon --profundidad=1 https://github.com/oca/maintainer-
quality-tools.git ${CASA}/maintainer-calidad-herramientas
- CAMINO de exportación=${CASA}/maintainer-calidad-
herramientas/travis:${CAMINO}
- travis_Instala_nightly
Guión:
- travis_Pruebas_
de carrera después
de que_éxito:
- travis_Después de_éxito_de pruebas
176
Capítulo 7

8. Cometer el archivo y empujarlo a


GitHub: $ git añade .travis.yml
$ git Cometer -m "añade travis
configuración" $ git origen de empujón

9. Va a vuestro travis-ci.org página y clic en el nombre de vuestro proyecto.


Tendrías que ver una primera complexión en progreso. Si vuestro código sigue el OCA
estándar de codificación, incluso pueda ser verde en la primera carrera:

177
Depuración y Testaje Automatizado

Cómo trabaja…
Cuándo habilitas Travis CI en un repositorio, Travis registra un gancho en GitHub. Por
default, el gancho provocará un Travis CI complexión para cada empujón a una rama del
repository y para cada petición de atracción. Peticiones de atracción están construidas en
un provisionales fusionar del PR, para asegurar que el fusionó las ramas pasan las pruebas.
El Travis CI archivo de configuración propuso aquí es bastante adelantado y muy cercano al
encontrado en los archivos_de muestra subdirectory del maintainer-calidad -las
herramientas te proyectan puede ver en https://github.com/oca/maintainer-
quality-tools ( sacamos el transifex la configuración utilizó para dirigir traducciones de
módulo). Aquí es una explicación del personalizó secciones en el archivo:

faddons: Esto tiene nada para hacer con Odoo addon módulos. Está utilizado para
preguntar Travis parainstalar algunos Ubuntu los paquetes que utilizan paquetes
de distribución en el entorno de testaje. Esto nos salvo de enparar paquetes de Pitón
como pitón-lxml de fuente, el cual toma mucho tiempo.
fenv: Esta sección define variables de entorno y la matriz de complexión. El
maintainerherramientas de calidad utilizan estas variables de entorno para saber
qué para probar, y correrá each env línea en una carrera de prueba separada:
‰‰ VERSIÓN: Esto es el Odoo versión para probar en contra.
‰‰ CONTROL_de PELUSA: Uso 0 para una complexión sin escama8 o
Pylint pruebas, y 1 otherwise. En la matriz, pusimos la primera
complexión para actuar el control de pelusa, cuando esto esf ast y
queremos retroalimentación rápida si los estándares de codificación no
son conocidos o si el linter encuentra errores.
‰‰ PRUEBAS: Uso 0 para una complexión en qué las pruebas de módulo no
son corridas; otherwise uso 1.
‰‰ ODOO_REPO: Esto es el GitHub repositorio para Odoo para probar contra
when las PRUEBAS es 1. En la receta, instalamos una complexión
contra ambos el oficial https://github.com/odoo/odoo
repositorio y el comunitario backports https de
repositorio://github.com/OCA/OCB. Si unset,
Sólo el repositorio oficial está utilizado.

fInstala: Estas secciones descargamaintainer-calidad-


herramientasen el entornode complexión y llama el
travis_instala_nightly utilidad, el cual instalará Odoo en Travis para ti.
fGuión: Este section llamatravis_pruebas_de carrerade
maintainer-calidad-herramientas. Esto es el guión en cargo de
comprobar las variables de entorno de la matriz de complexión y actuando las
acciones apropiadas.
fDespués de que_éxito: Después de las pruebas en la sección de guión han
corrido successfully, eltravis_después de que_guión_de éxito de la
prueba está corrido. En el contexto de la receta, este guión comprobará la
cobertura de prueba de los módulos que utilizan https://coveralls.io y
producir un informe en la complexión.

178
8
Backend
Vistas
En este capítulo, cubriremos los temas siguientes:
fffffff
f

f

f

f

f

f

f

f

f

f


n de ventana
A
ñ Teniendo una acción abre una vista concreta
a Añadiendo contenido y widgets a una
di
vista de forma que Añade perotoneladas
e
n a formas
d Pasando parámetros a formas y acciones: Contexto
o
u Definiendo filtros oficialmente listas: Ámbito
n Vistas de
el
e Búsqueda de
m vistas de lista
e
n Cambiando existiendo vistas:
t Documento de herencia de la Vista-
o
formas de estilo
d
e Elementos de forma dinámica que
c utilizan attrs Embedded vistas
a
rt Kanban views
a Espectáculo kanban tarjetas en columnas según su
y
a Calendario estatal y gantt vistas
c Graph Y el pivote ve
ci
ó QWeb informes

179
Backend Vistas

Durante este capítulo, supondremos que tienes una base de datos con la base addon
instalado y un empty Odoo addon módulo donde añades XML código de las recetas a un
archivo de dato referenced en el addon es manifiesta. Refiere a Capítulo 3, Creando Odoo
Módulos para cómo para activar cambios en vuestro addon.

Introducción
Este capítulo cubre todo el UI elementos tusuarios de sombrero están afrontados con
cuándo utilizan cualquier cosa otro que la parte de sitio web de Odoo. Históricamente, esto
básicamente era todo de OpenERP, tan también en un Odoo contexto, es a menudo justo
referido a como el cliente de web. Para ser más concreto, llamaremos este the backend
como opposed al sitio web frontend.

Añadiendo un elemento de carta y acción


de ventana
La manera más obvia para hacer una característica nueva disponible a los usuarios es por
utilizar un elemento de carta. Cuándo te clic en un elemento de carta, algo pasa. Estos
paseos de receta tú a través de cómo para definir que algo.
Crearemos una carta de nivel superior que muestra un sub carta en la barra de carta de
mano izquierda, abriendo una lista de todos los clientes.
Esto también puede ser hecho utilizando la interfaz de usuario de la web, vía la carta de
encuadres, pero preferimos utilizar XML archivos de dato desde este es qué tendremos que
utilizar cuándo creando nuestro addon módulos.

Cómo para hacerlo...


En un archivo de dato del XML de nuestro addon módulo, actuar los pasos siguientes:

1. Definir una acción para ser ejecutada:


<Ventana_de acto id="acción_todos los _clientes"
nombran="Todo clientes"
res_modelo="res.Árbol" de modo_de
vista="de socio,ámbito" de
forma="[('cliente', '=', Cierto)]"

Contexto="{'default_cliente':
límite}" Cierto="80" />

2. Crear la estructura de carta:


<menuitem id="La carta_hecha de
encargo_toplevel"
nombrar="Mi carta hecha de
encargo" />
<menuitem id="Costumbre_de carta_dejó"

180
Capítulo 8
Costumbre="de carta_del padre_toplevel"
Nombre="Esto aparecerá en la barra izquierda" />

3. Refiere a nuestra acción en carta:


<menuitem id="Carta_toda_carta" de
padre="de los
clientes_acción_de acción"
izquierda="hecho_toda_secuenc
ia" de clientes="10"
Grupos="" />

Si nosotros ahora upgrade el módulo, veremos una carta de nivel superior que abre un sub
carta en la barra de carta izquierda. Clicking En aquel elemento de carta abrirá una lista de
todos los clientes.

Cómo trabaja...
El primer elemento de XML, ventana_de acto, declara una acción de ventana para
mostrar una vista de lista con todos los clientes. Utilizamos los atributos más
importantes:
f Nombre: para ser utilizado como el título para las vistas abrió por la acción.
fres_Modelo: Esto es el modelo para ser utilizado. Estamos
utilizandores.Socio, donde Odooalmacena todos los socios y añadirresses,
incluyendo clientes.
fModo_de vista: Esto lista los tipos de vista para hacer disponible. El default el
valor es árbol,vista, haciendo disponible la lista y vistas de forma. Otras
elecciones posibles son kanban, graph, calendario, y gantt , explicó más tarde en
este chapter.
fÁmbito: Esto es opcional y te dejas para poner un filtro en los registros de ser
hechosdisponibles en las vistas. En este caso, queremos limitar los socios a sólo
los que son clientes . Explicaremos esto con más detalle en una receta dedicada
más tarde.
fContexto: Esto puede poner los valores hicieron disponibles al abrió vistas,
afectando sucomportamiento. En nuestro ejemplo, en registros nuevos queremos
la bandera de cliente default valor para ser Cierto. Esto será cubierto en más
profundidad en otra receta.
fLímite: Esto pone el default cantidad de registros que puede ser visto encima
vistas de lista. Éldefaults a 80 .
Luego creamos la jerarquía de elemento de la carta; de la carta de nivel superior al
clickable elemento de carta del fin. Los atributos más importantes para el menuitem el
elemento es:
fNombre: Esto está utilizado como el texto la exhibición de elementos de la carta. Si
vuestros enlaces de elemento de la carta a unaacción puedes dejar esto fuera,
porque en aquel caso el nombre de la acción será utilizado.
fPadre(padre_idsi utilizando elelementorécord): Esto es el XML ID
referencingla carta de padre élem. Los elementos sin padre son cartas de nivel
superior.
fAcción: Esto es el XML ID referencing la acción para apellidarse. Elementos de carta

únicasin elementos de niño son clickable, así que esta opción es sólo eficaz en
aquellos casos.

181
Backend Vistas

f sequence: Esto suele orden sibling elementos de carta.


fGrupos(grupos_idcon la etiquetarécord): Esto es una lista opcional del
usuario agrupaque puede acceder este elemento de carta. Si vacío, sea disponible
a todos los usuarios.
Acciones de ventana automáticamente determinan el view para ser utilizados por mirar
arriba de vistas para el modelo de objetivo, con el tipo pretendido ( forma, árbol, y tan
encima) y eligiendo el con el número de secuencia más bajo.
Ventana_de acto y menuitem es atajo conveniente XML etiquetas que esconder qué
de hecho estás haciendo: creas un registro de los modelos ir.Acciones.Ventana_de
acto e ir.ui.Carta respectivamente.

Ser consciente que los nombres utilizaron con el menuitem el atajo


puede no el mapa al campo nombra utilizado cuándo utilizando un
elemento récord: el padre tendría que ser padre _id y los grupos
tendrían que ser grupos _id.

Para construir la carta, el cliente de web lee todos los registros de ir.ui.Carta e infiere su
jerarquía del padre_id campo. Las cartas son también filtró basado encima permisos
de usuario a modelos y grupos asignaron a cartas y acciones. Cuándo unos clics de
usuario unos hombresu elemento, su acción está ejecutada.

Allí ha más...
Acciones de ventana también apoyan un atributo de objetivo para especificar cómo la
vista es para ser presentado. Las elecciones posibles son:
f Actual: Esto es el default y abre la vista en el cliente de web principal content
 área. Nuevo: Esto abre en un popup.
f inline: Esto hace la mayoría de sentido para formas. Abre una forma en el editar modo
pero tampoco con los botones estándares para editar, crea, o eliminar, ni con el Más

carta de acciones.
f
inlineview: Esto es similar a inline, pero obolígrafos en el modo leído en vez de
editar.
f

El atributo_de tipo de la vista de la acción de ventana es mayoritariamente


obsoleto por ahora. El alternativo al defaultla forma es árbol , el cual causa
los grupos lista a render un árbol jerárquico. No confunde este atributo con el atributo_de
modo de la vista utilizado y explicado más temprano, el cual de hecho decide qué tipos de
vistas están utilizados.
hay también algunos los atributos adicionales disponibles para acciones de ventana que no
es apoyado por la etiqueta_de atajo de ventana de acto. Así que para utilizarles,
tenemos que utilizar el elemento récord con los campos siguientes:
fres_id: Si abriendo una forma, puedes tener abra un registro concreto por poner
su IDaquí. Esto puede ser útil para multi brujos de paso, o en casos cuándo a
menudo tienes que ver/editar un registro concreto.

182
Capítulo 8

f Vista_de búsqueda_id: Esto especifica una vista de búsqueda concreta


para utilizar para el árbol y graph vistas.
f Búsqueda_de coche: Esto es Cierto por default. Pone esto a Falso si buscando
vuestro objeto es muy tiempo y/o el recurso que consume. De este modo, elu ser
puede revisar la búsqueda
Parámetros y Búsqueda de prensa cuándo satisfechos. Con el default, la búsqueda
está provocada inmediatamente cuándo la acción está abierta.
Mantiene en importar que la barra de carta en el superior y la carta a la izquierda es todo
hecho del mismo material, los elementos de carta. La diferencia única es que los elementos
en la barra superior no tiene cualesquier cartas de padre, mientras los en la barra izquierda
tienen el elemento de carta respectivo de la barra superior cuando padre. En la barra
izquierda, la estructura jerárquica es más obvia.
También serar en importar que para razones de diseño, las primeras cartas de nivel en la
barra izquierda son rendered como amables de encabezamiento y estándar Odoo no asigna
una acción a ellos muy a menudo. Tan incluso si técnicamente puedes asignar una acción a
ellos, vuestros usuarios no soler clamerles y probablemente será confundido si les esperas
para hacer tan.

Ve también
Encontrarás una discusión más detallada de la XML ID referencia mecanismo en Capítulo
9, Dato de Módulo. Por ahora, justo mantener en mente que te puede poner referencias
de este modo y – muy importantly – que asuntos de orden. Si las etiquetas encima eran
inverted, el addon conteniendo este código de XML no instalaría porque menuitem
referiría a una acción desconocida.

Esto puede devenir un pitfall cuándo añades archivos de dato nuevo y


elementos nuevos durante vuestro proceso de desarrollo, porque
entonces el orden en qué añades aquellos archivos y los elementos no
necesariamente reflejan el orden serán cargados en una base de datos
vacía. Siempre comprobar antes de que despliegue si vuestro addon
instala en una base de datos vacía.

La acción type ir.Acciones.Ventana_de acto es el más común un, pero una carta
puede referir a cualquier tipo de acción. Técnicamente, es justo igual si enlazas a una
acción de cliente, una acción de servidor, o cualquiera otro modelo definido en el
ir.Acciones.* namespace. Justo difiere en what el backend marcas fuera de la acción.
Si necesitas justo un minúsculo mordió más flexibilidad en la acción concreta para
apellidarse, mirada a las acciones de servidor que regreso una acción de ventana en vuelta.
Si necesitas flexibilidad completa en qué te presente, mirada a las acciones de cliente
(ir.Acciones.Cliente) cuáles te dejáis para tener un usuario completamente hecho de
encargo interfaz. Pero sólo hacer tan tan último recurso cuando pierdes mucho Odoo
conveniente helpers cuándo utilizándoles.
183
Backend Vistas

Teniendo una acción abre una vista


concreta
Acciones de ventana automáticamente determinan la vista para ser utilizada, pero a
veces queremos una acción para abrir una vista concreta.
Crearemos una vista de forma básica para el modelo de socio y hacer la acción de
ventana específicamente lo abre.

Cómo para hacerlo...


1. Definir tél socio vista de forma mínima:
<Récord id="formar_todo_modelo" de
clientes="ir.ui.Nombre"> <de campo de la
vista="nombra">Todo nombre</de campo> <de campo
de clientes="modelo">res.Campo</de socio>
<Tipo de arco="de nombre" de
campo="xml"> <forma>
<Grupo>
<Grupo de nombre="de
nombre" /> </de campo>
</Forma>
</field>
</Récord>

2. Decir la acción de la receta anterior para utilizarlo:


<Récord id="acción_todo_modelo_de forma"
de los
clientes="ir.Acciones.Ventana_de
acto.Vista">
<Ventana de acto="de nombre_de campo_id"
ref="acción_toda_vista" /> <de nombre de campo="de
clientes_id" ref="forma_todos los _clientes" />
<Modo de vista="de nombre_de
campo">nombre</de campo> <de campo de
forma="secuencia">10</campo>
</Récord>

Ahora si abres vuestra carta y clic algún socio en la lista, tendrías que ver la forma muy
mínima justo definimos.
184
Capítulo 8

Cómo trabaja...
Este tiempo, utilizamos el código de XML genérico para cualquier tipo de récord aquello es,
el elemento récord con el requerido atribuye id y modelo . Tan más temprano, el id el
atributo es una cuerda arbitraria que tiene que ser único para vuestro addon. El atributo
de modelo refiere al nombre del modelo quieres crear. Dado que queremos crear una
vista, necesitamos crear un registro de modelo ir.ui.Vista. Dentro de este elemento,
pusiste campos cuando definidos en el modelo escogiste vía el atributo de modelo.
Para ir.ui.Vista, los campos cruciales son model y arco . El campo de modelo
contiene el modelo quieres definir una vista para, mientras el campo de arco contiene la
definición de la vista él. Vendremos a sus contenidos en a escasos mientras.
El campo de nombre, mientras no estrictamente necesario, es útil cuándo debugging problemas
con vistas, así que puestos lo a alguna cuerda que te dices lo que esta vista está pretendida para
hacer. El contenido de este campo no es mostrado al usuario, así que puedes rellenar todas las
pistas técnicas a tú que consideras sensato.
Si pusiste nada aquí, tú'll consigue un default conteniendo el nombre de modelo y tipo de
vista.

ir.Acciones.Ventana_de acto.Vista
El segundo registro definimos trabajos en unison con ventana_de acto definimos anteriormente.
Sabemos ya que por poner la vista de campo_id allí, podemos seleccionar qué vista está
utilizada para el primer modo de vista. Pero dado pusimos el modo de vista_del campo al
default árbol, forma, vista_id tendría que elegir una vista de árbol, pero queremos poner la
vista de forma, el cual viene segundo aquí.

Si te encuentras en una situación así, uso el modelo ir.Acciones.Ventana_de


acto.Vista, el cual te das bien grained control sobre qué vistas para cargar para qué tipo de
vista. Los primeros dos campos definieron aquí es un ejemplo de la manera genérica de referir a
otros objetos; mantienes el cuerpo del elemento vacío pero añadir un attribute llamó ref cuál
contiene el XML ID del objeto quieres referencia. Tan qué pasa aquí es que referimos a nuestra
acción de la receta anterior en la ventana_de acto_id campo, y referir a la vista nosotros
justo creados en la vista_id campo.
Entonces, though no estrictamente necesario, añadimos un número de secuencia para colocar
esta asignación de vista relativamente a las otras asignaciones de vista para la misma acción.
Esto es sólo pertinente si asignas vistas para modos de vista diferente por crear múltiple
ir.Acciones.Ventana_de acto.Registros de vista.

Una vez defines el ir.Acciones.Ventana_de acto.Registros


de vista, toman precedencia sobre qué rellenaste el campo_de modo de
la vista de la acción.
Tan con único el por encima de registros, no verás una lista en absoluto,
pero sólo una forma. Así que tendrías que añadir otro
ir.Acciones.Ventana_de acto.La vista graba señalar a una
vista de lista.
185
Backend Vistas

Añadiendo contenido y widgets a una vista


de forma
La receta anterior mostrada cómo para elegir una vista concreta para una acción. Ahora
demostraremos cómo para hacer la forma nosotros defined anteriormente más útiles.

Cómo para hacerlo...


1. Definir la vista de forma estructura básica:
<Récord id="formar_todo_modelo" de
clientes="ir.ui.Nombre"> <de campo de la
vista="nombra">Todo campo</de clientes>
<Modelo de nombre="del
campo">res.Nombre</de campo> <de campo de
socio="tipo" de arco="xml">
<Forma>
<!--Contenido de forma va aquí
--> </forma>
</Campo>
</Récord>

2. Para añadir una barra de cabeza, normalmente utilizado para botones de acción
y tubería de etapa, añade dentro de la forma:
<Encabezamiento>
<Nombre de objeto="de tipo" de
botón="abre_cuerda_de entidad"
comercial="Abre socio comercial"
class="oe_punto destacado" />
</Encabezamiento>

3. Añade campos a la forma, utilizando etiquetas de grupo a visually organizarles:


<Contenido de cuerda="del grupo"
nombra="mi_nombre"> <de nombre de
campo="de contenido" />
<Categoría de nombre="del campo_id"
widget="muchos2mucho_grupo" /> </de etiquetas>

Ahora la forma tiene que dispponer una barra superior con un botón y dos verticalmente
alineó campos.

Cómo trabaja...
Miraremos en el campo de arco del ir.ui.Modelo de vista. Aquí, todo que el usuario
ve pasa. Primero, nota que las vistas están definidas en XML ellos, así que necesitas pasar
t atribuya tipo="xml" para el campo de arco, otherwise el parser será confundido. Es
también obligatorio que vuestra definición de vista contiene bien formó XML, otherwise te
meterás en problemas cuándo cargando esta fragmento.

186
Capítulo 8

Ahora, andaremos a través de las etiquetas utilizaron anteriormente y summarize el otros


aquello es disponible.

Forma
Cuándo defines una vista de forma, es obligatorio que el primer elemento dentro del campo
de arco es un elemento de forma. Este hecho está utilizado internamente para derivar el
campode tipo del registro, el cual es por qué tú no es supuesto para poner este campo.
Verás esto mucho en código de legado aun así.

El elemento de forma puede tener dos legado se atribuye, los cuales son cuerda y versión .
En las versiones anteriores de Odoo, aquellos solieron decidir en la tetale viste en el
breadcrumb y para diferenciar entre las formas escritas en pre-7.0 estilo y después, pero
ambos pueden ser considerados obsoletos por ahora. El título en el breadcrumb es ahora
inferido del nombre del modelo_consigue función, mientras la versión es tansumed para
ser 7.0 o encima.
Además de los elementos listaron luego, puedes utilizar HTML arbitrario dentro de la
etiqueta de forma. El algoritmo es que cada elemento desconocido a Odoo está considerado
HTML sencillo y sencillamente pasado a través de a el navegador. Ser prudente con aquel,
cuando el HTML rellenas puede interaccionar con el código de HTML el Odoo los elementos
generan, el cual podría distorsionar el rendering.

Encabezamiento
Este elemento es un contenedor para los elementos que tendría que ser mostrado en el
encabezamiento de una forma, el cual es rendered como barra gris. Normalmente, cuando
en este ejemplo, colocas botones de acción aquí o una barra de estado si vuestro modelo
tiene un campo estatal.

Botón
El elemento de botón suele dejar el usuario para provocar una acción. Ver la receta
siguiente
Añadiendo botones a formas para detalles.

Grupo
El elemento de grupo es Odoo medio principal para organizar contenido. Los campos
colocados dentro de un elemento de grupo es rendered con su título, y todos los campos
dentro del mismo grupo están alineados de modo que allí ha también un indicador visual
que pertenecen juntos. Puedes también nest los elementos de grupo; esto causa Odoo a
render el contuvo campos en columnas adyacentes.
En general, tendrías que utilizar este mecanismo para todos vuestros campos y únicos revert
a otros métodos
(Ve próximo) cuándo necesario.

Si asignas la cuerda de atributo en un grupo, su contenido será rendered como


encabezar para el grupo.
Tendrías que desarrollar el hábito de asignar un nombre a cada grupo lógico de
campos también. Este nombre no es visible al usuario, pero muy útil cuándo nosotros
override vistas en las recetas siguientes. Mantener el nombre único dentro de una
definición de forma para evitar confusión sobre qué grupo refieres a.

187
Backend Vistas

Campo
Para de hecho espectáculo y manipular dato, vuestra forma tendría que contener algunos
elementos de campo. Tienen uno obligatorio attribute nombre, el cual refiere al nombre
del campo en el modelo. Tan encima, ofrecemos el usuario para editar el nombre y las
categorías del socio. Si sólo queremos mostrar uno de ellos, sin el usuario que es capaz
de editar el campo, pusimos el atributo readonly a 1 o Cierto . Este atributo de
hecho puede contener un subconjunto pequeño de código de Pitón, tan
readonly="2>1" haría el campo leído sólo demasiado. El mismo aplica al atributo
invisible, que te uso para tener el valor leído de la base de datos, pero no mostrado al
usuario. Veremos más tarde en qué situaciones queremos tener aquello.

Cuida no para poner el mismo campo dos veces en vuestra


forma. Odoo No es diseñado para apoyar esto, y el resultado será
que todo pero uno de aquellos campos behave como si eran
vacíos.

Tienes que haber notado el atributo widget en el campo de categorías. Define cómo el
dato en el campo está supuesto para ser presentado al usuario. Cada tipo de campo tiene
su estándar widget, así que no tienes que explícitamente escoger un widget. Pero varios
tipos proporcionan multiple maneras de representación, en qué caso podrías optar para
algo más que el default. Como lista completa de disponible widgets superaría el alcance de
esta receta, tendrás que recurrir a Odoo código de fuente para probarles fuera y consultar
Capítulo 15, Desarrollo de Cliente de la Web para detalles encima cómo para hacer vuestro
propio.

Atributos generales
Encima más elementos (esto incluye grupo, campo, y botón ), puedes poner los atributos
attrs y grupos . Mientras attrs está hablado luego, el atributo de grupos te das el
possibility para mostrar algunos elementos sólo a los miembros de grupos seguros.
Sencillamente puesto el grupo XML ID (separado por comas para grupos múltiples) en el
atributo, y el elemento será escondido para todo el mundo quién no es un miembro de al
menos uno de los hombres de grupostioned.

Otras etiquetas
Hay situaciones donde te podría querer deviate de los grupos de diseño estrictos
prescribieron. Un ejemplo bueno es, si quieres el campo de nombre de un récord de ser
rendered como encabezar, la etiqueta del campo interferiría con el aspecto. En este caso, no
pone vuestro campo a un elemento de grupo, pero por ejemplo, al HTML sencillo h1
elemento. Entonces antes del h1 elemento, puesto un elemento de etiqueta con el para
atribuir puesto a vuestro nombre de campo:
<Etiqueta para="nombre" />
<h1><nombre de campo="nombre"
/></h1>
Esto será rendered con el contenido del campo como grande encabezando, pero el nombre
del campo sólo pequeño encima. Aquello es básicamente lo que el socio estándar forma
hace.

188
Capítulo 8

Si necesitas una rotura de línea dentro de un grupo, uso el newline elemento. Es siempre
vacío.
<newline />

Otro elemento útil es el footer elemento. Cuándo abres una forma como popup, esto es el
sitio bueno para colocar los botones de acción. Sea rendered como barra gris también,
análogo al elemento de encabezamiento.

Allí ha más...
Desde entonces vistas de forma son básicamente HTML con algunas extensiones, Odoo
también hace uso extenso de CSS clases. Dos muy útil unos son oe_leídos_sólo y
oe_edita_sólo – causan los elementos con estas clases aplicaron para ser visibles sólo en
modo/de vista leída o sólo en editar modo. Así que para tener la etiqueta visible sólo en
editar modo:
<Etiqueta para="clase" de nombre="oe_edita_sólo" />

Más allá, el elemento de forma puede tener los atributos crean, edita, y eliminar . Si
pusiste uno de aquellos a falso , la acción correspondiente no será disponible para esta
forma. Sin este ser explícitamente puesto, la disponibilidad de la acción está inferida de los
permisos del usuario. Nota que esto es puramente para alisar el UI; no utiliza esto para
seguridad.

Ve también
El widgets describió más temprano ya ofrecer mucha funcionalidad, pero tarde o temprano
encontrarás casos donde ellos no exactamente qué quieres. Para definir vuestro propio
widgets, refiere a Capítulo 15, Desarrollo de Cliente de la Web.

Añadiendo botones a formas


Añadimos un botón en la forma anterior, peroel re es tipos bastante diferentes de botones
para utilizar. Esta receta añadirá otro botón; también puesto el código siguiente en al
elemento de encabezamiento de lareceta anterior.

Cómo para hacerlo...


Añadir un botón que refiere a una acción:

<Nombre de acción="de tipo" de botón="%(base.Forma_de categoría_de


socio_de acción)d" cuerda="categorías de socio Abierto" />
189
Backend Vistas

Cómo trabaja...
El atributo de tipo del botón determina el semantics de los otros campos, así que nosotros
primero mirada a los valores posibles:
fAcción: Esto hace el botón llama una acción cuando definido
enir.Acciones.*namespace. Las necesidades de atributo del nombre para
contener la base de datos de la acción id, el cual te oportunamente puede mirar
arriba con una cuerda de formato de la pitón que contiene el XML ID de la acción en
cuestión.
fObjeto: Thes llama un método del modelo actual. Elatributode nombre
contiene el nombre de lafunción. La función tendría que tener la firma
@api.multi Y actuará en el registro actualmente visto.
fworkflow: Esto envía un workflow señal al registro actual.
Elnamenecesidadesde atributo para contener el nombre de la señal. Uso el
atributo de estados para hacer el workflow los botones sólo disponibles en
estados donde ellos de hecho algo, aquello es, en estados que tiene las
transiciones provocaron por la señal en cuestión.
La cuerda attribute suele asignar el texto el usuario ve.

Allí ha más...
Uso CSS clases btn-primarios a render un botón que está destacado (actualmente
azul) y btn-default a render un botón normal. Esto es generalmente utilizado para el
cancelar botones en brujos o para ofrecer acciones secundarias en un visually manera
discreta.
La llamada con un botón de objeto de tipo puede regresar un diccionario que describe una
acción, el cual entonces será ejecutado en el lado de cliente. De este modo puedes
implementar multi brujos de pantalla o justo abrir algunos otsu registro.

También puedes tener contenido dentro de la etiqueta de botón, reemplazando el


atributo de cuerda. Esto es generalmente utilizado en el botón boxea tan descrito en
las formas de estilo de Documento de receta.

Pasando parámetros a formas y


acciones: Contexto
Internamente, cada method en Odoo tiene acceso a un diccionario contexto llamado que
está propagado de cada acción a los métodos implicó en entregar que acción. El UI también
tiene acceso a él y puede ser modificado en varias maneras por poner valores en el
contexto. En esta receta, we'll explora algunos de las aplicaciones de este mecanismo por
toying con la lengua, default valores, y filtros implícitos.
190
Capítulo 8

Preparándose
Mientras no estrictamente necesario, esta receta será más divertida si instalas el francés
language, en caso no empezaste fuera con esta lengua en primer lugar. Consulta Capítulo 11,
Internacionalización, para cómo para hacer este. Si tienes una base de datos francesa, cambio
fr_FR a algunos otra lengua; en_EE.UU. harán para ingleses. También, clic el botón Not archived
encima uno de vuestros clientes para archivo él y verificar que este socio no aparece más en
La lista.

Cómo para hacerlo...


1. Crear una acción nueva, muy similar al de la primera receta:
<Ventana_de acto id="acción_todos los
_clientes_fr" nombre="Tous
les clientes"
res_modelo="res.Socio"
Ámbito="[('cliente', '=', Cierto)]"
Contexto="{'lang': 'fr_FR', 'default_lang':
'fr_FR', 'prueba_activa': Falso}" />

2. Añadir una carta que llamadas esta acción. Esto queda como un ejercicio para el lector.

Cuándo abres esta carta, las vistas aparecerán en franceses, y si creas un socio nuevo,
tenga francesa como el preselected lengua. Una menos diferencia obvia es que también
verás el socio tú deactivated más temprano.

Cómo trabaja...
El contexto dictionary está poblado de varias fuentes. Primero, algunos valores del
El registro del usuario actual (lang y tz , para la lengua del usuario y el usuario timezone) está
leído, entonces hay addons aquello añade llaves para sus propósitos propios. Más allá, el UI
añade llaves about qué modelo y qué registro somos ocupados con en el momento ( activo_id,
activo_ids, modelo_activo). Y cuando visto anteriormente, también podemos añadir
nuestras llaves propias en acciones. Aquellos están fusionados juntos y pasados a las funciones
de servidor subyacentes, y también alc lient lado UI.

Tan por poner el lang llave de contexto, forzamos la lengua de exhibición para ser
francés. Notarás que esto no cambia el entero UI lengua, el cual es porque sólo la vista de
lista que abrimos mentiras dentro del alcance de este contexto. El resto of el UI estuvo
cargado ya con otro contexto que contuvo la lengua original del usuario. Pero si abres un
registro en esta vista de lista, sea presentado en francés también, y si abres algunos
enlazaron récord en la forma o pulsar un botón que ejecuta una acción, la lengua será
propagada también.
191
Backend Vistas

Por poner default_lang, pusimos un default valor para cada récord creado dentro del
Alcance de este contexto. El patrón general es default_$fieldname: mi_default_valor, el
cual enables te para poner default valores para los socios nuevamente creados en este caso. Dado
que nuestra carta es sobre clientes, pueda haber hecho sentido a también puesto
default_cliente:
Cierto de tener el campo de Cliente comprobado por default. Pero esto es un modelo
ancho default para res.Socio en todo caso, así que esto no habría cambiado cualquier
cosa. Para campos escalares, la sintaxis para este es tan escribirías él en código de Pitón –
campos de cuerda entran cita, numera justo gusta que, y los campos booleanos son
cualquier Ciertos o Falsos . Para relational campos, la sintaxis es ligeramente más
complicada – referir a Capítulo 9, Dato de Módulo , para cómo para escribir aquellos. Nota
que el default los valores puestos en el contexto override el default los valores puestos en la
definición de modelo, así que puedes tener diferente default valores en situaciones
diferentes.
La última llave es prueba_activa , el cual tiene muy especial semantics. Para cada modelo
que tiene un campo llamó activo, Odoo automáticamente filtros fuera de los registros donde
este campo es Falso. Esto es por qué el socio donde tú unchecked este campo desaparecido
de la lista. Por poner esta llave, podemos suprimir este comportamiento.

Esto es útil para el UI en su derecho propio, pero aún más útil en


vuestro código de Pitón cuándo necesitas ser seguro alguna
operación está aplicada a todos los registros, no justo el activos
unos.

Allí ha más...
Mientras definiendo un contexto tienes acceso a algunas variables, la mayoría de
importantes uno siendo uid, el cual evalúa al usuario actual ID. Necesitarás esto para
poner el default filtros
(Ve la receta próxima). Más allá, tú have acceso al contexto de función_hoy y la
fecha actual_variable, donde el primero es un objeto de fecha que representa la
fecha actual cuando visto del huso horario del usuario y el último la fecha actual cuando
visto en UTC, formatted tan YYYY-MM-DD. Para poner un default para un campo de
fecha a la fecha actual por default, uso fecha_actual y, para default filtros, contexto
de uso_hoy().

Más allá, puedes hacer algunos cálculos de fecha con un subconjunto de Pitón
datetime, tiempo, y relativedelta clases.
192
Capítulo 8

Por qué la charla repetida aproximadamente 'un subconjunto de Pitón'?


Para varias razones técnicas, los ámbitos tienen que ser evaluados también
en el lado de cliente cuando en el lado de servidor. Evaluación de lado del
servidor existió más temprana, allí la pitón llena era disponible (pero está
restringido por ahora demasiado para razones de seguridad). Cuándo
evaluación de lado del cliente estuvo introducida, la opción mejor en
ordena no para romper el sistema entero era para implementar una parte
de Pitón en Javascript. Tan hay un intérprete de Pitón de Javascript
pequeño construido a Odoo cuál trabaja grande para expresiones sencillas,
y aquello es normalmente bastante.
Beware Sobre variables en el contexto conjuntamente con el
<atajo_de ventana /> del acto. Aquellos están evaluados en
tiempo de instalación, el cual es casi nunca qué quieres. Si
necesitas variables en vuestro contexto, uso <sintaxis /> récord.

La misma manera que añadimos algunas llaves de contexto en nuestra acción, podemos
hacer con botones. Esto causa la función o acción las llamadas de botón para ser corridos
en el contexto dado y por ahora sabes algunos de los trucos puedes estirar de este modo.
La mayoría de elemento de forma atribuye aquello está evaluado tan la pitón también tiene
acceso al diccionario de contexto. Los atributos invisibles y readonly es tales atributos. Tan
en casos donde quieres un elemento para aparecer en una forma a veces, pero no en otro
tiempo, pusiste el atributo invisible a contexto.Consigue( soyy_llave'), y para acciones
que ventaja al caso donde el campo está supuesto para ser invisible, pusiste la llave de
contexto mi_llave: Cierto. Tal estrategia te habilitas para adaptar vuestra forma sin having
para reescribir él para ocasiones diferentes.

Puedes también puesto un contexto en campos relacionales, el cual influye cómo el campo
está cargado. Por poner la vista de forma_de las llaves_ref o vista_de árbol_ref al
XML ID de una vista, puedes seleccionar una vista concreta para este field. Esto es
necesario cuándo tienes vistas múltiples del mismo tipo para el mismo objeto. Sin esta llave
consigues la vista con el número de secuencia más bajo, el cual puede no siempre ser
deseable.

Ve también
Uno de las aplicaciones muy útiles del contexto is para poner default la búsqueda filtra tan
descrita en las vistas de Búsqueda de la receta.

Definiendo filtros oficialmente listas: Ámbito


Ya hemos visto el primer ejemplo de un ámbito en la primera acción, el cual era
[('Cliente', '=', Cierto)]. Es un uso muy común caso when necesitas mostrar un
subconjunto de todos los registros disponibles de una acción, o para dejar sólo un subconjunto
de registros posibles para ser el objetivo de un mucha2una relación. La manera de describir
estos filtros en Odoo se apellida un ámbito. Esta receta ilustra cómo para utilizar tal ámbito
para mostrar una selección de socios.

193
Backend Vistas

Cómo para hacerlo...


Para mostrar un subconjunto de socios de vuestra acción, necesitas actuar los pasos
siguientes:

1. Añadir una acción para no-francés hablando clientes:


<Récord id="iónde acto_mi_modelo" de
clientes="ir.Acciones.Nombre_de campo"> <de ventana de
acto="nombre">
Todos los clientes que no hablan
campo </francés>
<Nombre de campo="res_modelo">res.Nombre</de
campo> <de campo de socio="ámbito">
[('Cliente', '=', Cierto), ('usuario_id', '=', uid),
('lang', '!=', 'fr_FR')]
</Campo>
</Récord>

2. Añadir una acción para los clientes quiénes son clientes o proveedores :
<Récord id="clientes_de acción_o_modelo"
de
proveedores="ir.Acciones.Ventana_d
e acto">
<Clientes de nombre="de nombre">de campo o
nombre</de campo> <de campo de
proveedores="res_modelo">res.Nombre</de campo> <de
campo de socio="ámbito">
['|', ('cliente', '=', Cierto), ( esupplier', '=',
Cierto)] </campo>
</Récord>

3. Añade cartas que llamada esta acción. Esto queda como un ejercicio para el lector.

Cómo trabaja...
La forma más sencilla de un ámbito es una lista de 3-tuples que contains un nombre de campo
del modelo en cuestión tan cuerda en el primer elemento, un operador cuando cuerda en el
segundo elemento, y el valor el campo es para ser comprobado en contra como el tercer
elemento. Esto es qué hicimos en la primera acción, y esto está interpretado cuando: Todas
aquellas condiciones tienen que aplicar a los registros somos
Interesado en. Esto de hecho es un atajo, porque los ámbitos saben los dos operadores de prefijo
& y | , dónde & es el default. Tan, en forma formal, el primer ámbito sería escrito cuando ['&',
'&', ('cliente', '=', Cierto), ('usuario_id', '=', uid), ('lang',
'!=', 'fr_FR')].
Mientras un poco duro de leer para expresiones más grandes, la ventaja de operadoras de
prefijo es que su alcance es rigidly definido, el cual te salvas prpers teniendo que preocupar
aproximadamente operador precedence y paréntesis. Es siempre el siguiente dos
expresiones: El primero & aplica a ' &', ('cliente', '=', Cierto),
('usuario_id', '=', uid) como el primer operando y
('lang', '!=', 'fr_FR') como el segundo. Entonces, el segundo & aplica a ('cliente',
'=', Cierto) como el primer operando y ('usuario_id', '=', uid) como el segundo.
194
Capítulo 8

En la segunda acción, tenemos que escribir fuera de la forma llena porque necesitamos el |
operador.

hay también un ! Operador para negación, pero, equivalencias lógicas dadas y negated
operadores de comparación como != Y no en, no es realmente necesario. Nota que esto
es un unary operador de prefijo, así que sólo aplica a la expresión siguiente en el ámbito y
no a todo aquello sigue.
Nota que el operando correcto no necesita para ser un valor fijo cuándo escribes un ámbito
para una acción de ventana u otros ámbitos de lado del cliente. Puedes utilizar la misma
Pitón mínima cuando
Descrito más temprano para contextos, así que puedes escribir filtros como cambiados
última semana, mis socios, y tan encima.

Allí ha more...
Los ámbitos de preceder trabajan sólo en campos del modelo él, mientras a menudo
necesitamos filtrar basados en las propiedades de enlazó registros. Para hacer este, puedes
utilizar la notación también utilizada en
@api.Depende definiciones o relacionó campos: crear un salpicado path del modelo actual al
modelo quieres filtro para. Para buscar socios qué tener una persona de ventas que es un
miembro de un grupo que empieza con el G de letra, utilizarías el ámbito
[('user_id.groups_id.name', '=gusta', 'G%')]. El camino puede ser arbitrarily mucho
tiempo, así que sólo tienes que cuidar que hay campos de relación entre el modelo actual y el
modelo quieres filtro para.

Operadores
La mesa siguiente lista los operadores disponibles y su semantics:

Operador
(equivalente) Semantics
=, != (<>) Partido exacto, no igual (deprecated notación de no igual)
Controles si el valor es uno de los valores nombraron en una lista en el
En, no en correcto
Operando, dado como lista de Pitón: [('uid', 'en', [1, 2,
3])]
<, <= Más grande que, más grande o igual
>, >= Less que, menos o igual
Gusta, no gustar Controles si el operando correcto está contenido (subcadena) en el valor
ilike, no ilike Igual como el precediendo un pero el caso insensible
=Gusta, =ilike Puedes buscar patrones aquí: % partidos cualquier cuerda y _.
Mateches un carácter. Esto es el equivalente de PostgreSQL es gusta .
Niño_de Para modelos con un padre_id campo, esto busca niños del
Operando correcto, con el operando correcto incluido en los resultados.
Evalúa a cierto si el operando correcto esf alse, otherwise él behaves
=? gusta
"= -" Esto es útil cuándo generas ámbitos programmatically y
Quiere filtro para algún valor si está puesto, pero ignorarlo otherwise.

195
Backend Vistas

Pitfalls
Esto todo trabaja bien para campo tradicionals, pero un problema notorio está buscando el valor
de una función no almacenada campo. Es un problema que las personas a menudo omiten la
función de búsqueda, mientras esto es bastante sencillo para fijar por proporcionar la función
de búsqueda en vuestro código propio cuando descrito en
Capítulo 4, Modelos de Aplicación.

Otro asunto que podría desconcertar los desarrolladores es Odoo comportamiento cuándo
buscando a través de uno2muchos o muchos2muchos campos con un operador negativo.
Imagina tienes un socio con una etiqueta Un y buscas [('category_id.name', '!=',
'B')]. Vuestro socio aparece en el resultado y esto es qué esperaste. Pero si añades la
etiqueta B a este socio, él todavía
Aparece en vuestros resultados, porque para el algoritmo de búsqueda es bastante que hay uno
registro enlazado (Un en este caso) que hace not cumplir el criterio. Ahora si sacas la etiqueta Un
de modo que B es la etiqueta única, el socio será filtrado fuera. Si también sacas la etiqueta B de
modo que el socio no tiene ninguna etiqueta, es todavía filtrado fuera, porque condiciones en el
enlazó los registros presuponen tél existencia de este registro. En otras situaciones aun así, esto
es el comportamiento quieres, así que no es realmente una opción para cambiar el
comportamiento estándar. En caso necesitas un comportamiento diferente aquí, proporcionar
una función de búsqueda de vuestro propio aquello interpreta el negation la manera necesitas.

Un pequeño gotcha es que las personas olvidan están escribiendo XML


archivos cuándo es sobre ámbitos. Necesitas huir el menos-que
operador. Buscando graba aquello ha sido creado antes de que hoy
tendría que ser
[('Crear_fecha', '&lt;', fecha_actual)] en XML.

Ve también
Si nunca necesitas manipular un ámbito no creaste programmatically, uso la utilidad
funciona proporcionada en openerp.osv.Expresión. Especialmente es_hoja,
normaliza_ámbito, Y ,y O te dejará para combinar domains exactamente la
manera Odoo él. No esto tú, porque hay muchos casos de esquina tienes que
tener en cuenta y es muy probable pasarás por alto uno.
Para la aplicación estándar de ámbitos, ver las vistas de Búsqueda de la receta.

Vistas de lista
After Habiendo gastado bastante algún tiempo en la vista de forma, ahora tendremos una
mirada rápida en cómo para definir vistas de lista. Internamente, se apellidan vistas de
árbol en algunos sitios y vistas de lista en otros, pero, dados hay otra construcción dentro
del Odoo vista framework llamó árbol, nos aferraremos a el wording lista aquí.
196
Capítulo 8

Cómo para hacerlo...


1. Definir vuestra vista de lista:
<Récord id="árbol_todo_modelo" de clientes="ir.ui.Vista">
<Modelo de nombre="del
campo">res.Nombre</de campo> <de campo de
socio="tipo" de arco="xml">
<Colores de árbol="azules: cliente y
proveedor; verde:cliente;
Rojo: nombre">
<de nombre de campo="de
proveedor" />
<Cliente de nombre="del campo"
invisible="1" /> <nombre de campo="el
proveedor" invisible="1" />
</Árbol>
</Campo>
</Récord>

2. Decir la acción de la primera receta para utilizarlo:


<Récord id="acción_todo_modelo_de árbol" de los
clientes="ir.Acciones.Ventana_ de acto.Vista">
<Ventana de acto="de nombre_de campo_id"
ref="acción_toda_vista" /> <de nombre de campo="de
clientes_id" ref="árbol_todos los _clientes" />
<Secuencia de nombre="del
campo">5</registro> </de campo>

Cómo trabaja...
Tú already saber la mayoría de qué pasa aquí. Definimos una vista, este tiempo de árbol de tipo,
y sujetarlo a nuestra acción con un ir.Acciones.Ventana_de acto.Elemento de vista. Así
que la cosa única dejó para hablar es el elemento de árbol y su semantics. Con una lista no
tienes muchos deelecciones de señal, así que los niños válidos únicos de este elemento son el
campo y elementos de botón.
Siguen el mismo semantics como más tempranos, salva para el hecho que hay mucho
menos elecciones para widgets – el sólo elecciones realmente interesantes son
progressbar, mcualquier2onebutton, y mango . El primer dos behave como sus
tocayos de forma. El mango es concreto de listar vistas. Está significado para campos
de entero y renders un arrastrar mango que el usuario puede utilizar para arrastrar una fila
a una posición diferente en la lista, así actualizando el valor del campo. Esto es útil para
secuencia o campos de prioridad.
Qué es nuevo aquí es el atributo de colores en el elemento de árbol. Contiene gobierna
qué color de fuente está escogido para la fila, dado en el color de forma: código de
Pitón, separado por puntos y comas. Elf irst el partido gana, tan lo que la vista anterior es a
render socios quiénes son ambos proveedor y cliente en azul, clientes en verdes, y
proveedores en rojos. En vuestro
Código de pitón, puedes utilizar los campos nombraste en la definición de vista, el cual es
por qué nosotros tiene que estirar el cliente y campos de proveedor también. Les
hicimos invisibles porque sólo necesitamos el dato y no quiere molestar nuestros usuarios
con aquellas dos columnas extras. Los colores posibles son los que HTML define, así que
puedes tampoco nombres de uso o un hex cuerda.
197
Backend Vistas

Allí ha más...
Para campos numéricos, puedes añadir una suma de atributo que causas esta columna
para ser summed arriba con el texto pusiste en el atributo como tooltip. Menos común es los
atributos avg, min, y max , aquella exhibición the media, mínimo, y máximo
respectivamente. Nota que estos cuatro trabajo único en los registros actualmente visibles,
así que podrías querer ajustar el límite de la acción (ve encima) en orden para el usuario
para ver todos los registros inmediatamente.
Análogo a los colores attribute en el elemento de árbol es el atributo de fuentes . Con
él, puedes escoger tener un récord ser intrépido, italic, o subrayar (sic). En la parte
correcta de una definición de fuente, puedes correr las mismas expresiones de Pitón tan
anteriormente. Hay una diferencia sutil though. Aquí, la última definición gana si las
expresiones múltiples aplican a una fila.
Un atributo muy interesante para el elemento de árbol es editable. Si pusiste esto a superior
o fondo , la lista behaves enteramente diferente que antes de que. Sin él, clicking una fila abre
una vista de forma
Para la fila. Con él, clicking una fila lo hace editable inline, con los campos visibles rendered
tan campos de forma. Esto es particularmente útil en embedded vistas de lista, los cuales
están hablados más tarde en este capítulo. La elección es si las líneas nuevas seránun dded
en el superiores o fondo de la lista.
Por default, los registros están ordenados según la _propiedad de orden del modelo
mostrado. El usuario puede cambiar ordenar por clicking un encabezamiento de columna,
pero puedes también puesto un orden inicial diferente por poner el default_propiedad
de orden en el elemento de árbol. La sintaxis es el mismo tan en _orden.

Ordenando es a menudo una fuente de frustración para desarrolladores nuevos.


Cuando Odoo deja
PostgreSQL El trabajo aquí, puedes sólo orden por campos que
PostgreSQL sabe aproximadamente y también sólo los campos que vivos
en la misma mesa de base de datos. Tan si quieres orden por una
función o un campo relacionado, ser seguro para poner la
tienda=Cierta. Si necesitas ordenar por un campo heredado de otro
modelo, declarar un almacenó campo relacionado.

El crear, edita, y eliminar unttributes del trabajo de elemento del árbol igual en
cuanto al elemento de forma describió más temprano. También determinan los controles
disponibles si el atributo editable está puesto.

Vistas de búsqueda
Cuándo abriendo vuestra vista de lista, notarás el campo de búsqueda al aparejo
superiorht. Si escribes algo allí, consigues sugerencias sobre qué para buscar y hay
también un conjunto de predefined filtros para escoger de. Esta receta andará tú a
través de cómo para definir aquellas sugerencias y opciones.
198
Capítulo 8

Cómo a do lo...
1. Definir vuestra vista de búsqueda:
<Récord id="buscar_todo_modelo" de
clientes="ir.ui.Modelo"> <de nombre de campo="de
vista">res.Campo</de socio>
<Tipo de arco="de nombre" de
campo="xml"> <búsqueda>
<Campo de nombre="de
nombre" /> <de campo
categoría="de nombre_id"
Ámbito_de filtro="[('categoría_id', 'niño_de',
self)]" />
<Banco de nombre="del campo_ids"
widget="mucho2un" /> <filtro
proveedores="de nombre"
Ámbito="de Proveedores" de la
cuerda="[( esupplier', '=', Cierto)]"
/>
</Búsqueda>
</Campo>
</Récord>

2. Decir vuestra acción para utilizarlo:


<Récord id="acción_todo_modelo" de clientes="ir.actions.Nombre_de
campo"> <de ventana de acto="nombra">Todo campo</de clientes>
<Nombre de campo="res_modelo">res.Campo</de socio>
<Ámbito de nombre="del campo">[('cliente', '=',
Cierto)]</búsqueda> <de nombre de campo="de campo_vista_id"
ref="busca_todos los _clientes" />
</Récord>

Cuándo escribes algo ent busque barra ahora, serás ofrecido para buscar este plazo en el nombre,
categorías, y campos de cuentas del banco. Si vuestro plazo pasa para ser una subcadena de un
número de cuenta de banco en vuestro sistema, incluso serás ofrecido para buscar exactamente
para esta cuenta de banco.

Cómo trabaja...
En el caso de nombre , sencillamente listamos el campo cuando el para ser ofrecido al usuario
para buscar. Dejamos el semantics en el defaults, el cual es una subcadena busca campos de
carácter.
Para categorías, nosotros algo más interesting. Por default, vuestro plazo de búsqueda aplicó a
un muchos2mucha búsqueda de nombre de gatillos_de campo, el cual sería una búsqueda
de subcadena en el categorie nombres en este caso. Pero dependiendo de vuestra estructura de
categoría, pueda ser muy conveniente de buscar socios quiénes tienen la categoría estás
interesado en o un niño de él. Piensa aproximadamente
Una categoría principal Newsletter suscriptores con sub categorías Semanalmente
newsletter, Mensuales newsletter, y un par de otro newsletter tipos. Buscando newsletter
suscriptores con el preceding definición de vista de la búsqueda te dará todo el mundo
quién está suscrito a cualquiera de aquellos newsletters en uno va, el cual es mucho más
conveniente que buscando cada tipo solo y combinando los resultados.

199
Backend Vistas

El ámbito_de filtro attribute puede contener un ámbito arbitrario, así que eres tampoco
restringido a buscar el mismo campo nombraste en el atributo de nombre, ni a utilizar
sólo uno denomina. El variable self es lo que el usuario rellenó, y también la variable única
puedes utilizar aquí. Un más elaborate ejemplo del default vista de búsqueda para socias es:
<Filtro de nombre="de nombre" de campo_ámbito="['|','|', ('nombre_de
exhibición','ilike',self),( esf','=',self),('email','ilike',se
lf)]"/>

Esto deja el usuario a ni siquiera pensar mucho sobre qué para buscar; just tipo algunas
letras, golpe
Introduce, y, con un poco de suerte, uno de los campos mencionó contiene la cuerda
estamos buscando.

Para el banco_ids campo, utilizamos otro truco. El tipo de un campo no sólo decide el default
manera de buscar la entrada del usuario, también define la manera Odoo presenta las
sugerencias. Y dado muchos2un campos son el únicos unos aquella conclusión de coche de la
oferta, forzamos Odoo para hacer que, incluso aunque banco_ids es un un2mucho campo por
poner el widget atributo. Sin este, el offer sería sencillamente para buscar en este campo, sin
sugerencias de conclusión. El mismo aplica a muchos2muchos campos. Nota que cada campo
con un muchos2un widget el conjunto provocará una búsqueda en su modelo para cada uno del
usuario keystrokes – no utiliza demasiados de ellos.

También tendrías que poner el más utilizó campos hasta arriba, porque el primer campo es
qué está buscado si el usuario justo escribe algo y los golpes Introducen. También parece
valor mencionando que la barra de búsqueda es muy bien utilizable con el teclado;
seleccionar una sugerencia por pulsar el abajo flecha y abrir un muchos2unsugerencia de
conclusión por pulsar la flecha correcta. Si educas vuestros usuarios en este y parar
atención a un sensato ordenando de campos en la vista de búsqueda, serán mucho más
eficaces que por escribir algo primero, grabbing el ratón, y seleccionando alguna opción.

El elemento de filtro crea un botón que añade el contenido del atributo de ámbito del filtro
al ámbito de búsqueda. Tendrías que añadir un nombre internológico y
un atributo de cuerda a describe el filtro a vuestros usuarios.

Allí ha más...
Puedes agrupar los filtros con la etiqueta de grupo, el cual les causa para ser rendered
ligeramente más cercano junto que los otros filtros, pero esto tiene implicaciones semánticas
también. Si pusiste filtros múltiples en el mismo grupo y activar más de uno de ellos, sus ámbitos
serán combinados con el operador |, mientras filtros y campos no en el mismo grupo está
combinado con el operador &. Casos donde quieres la disyunción para vuestros filtros es cuándo
ellos filtra para mutually conjuntos exclusivos, en qué caso que selecciona tanto de ellos siempre
dirigirían a un conjunto de resultado vacío. Dentro del mismo grupo, puedes conseguir el mismo
efecto con el separator elemento.

Nota que si el usuario rellena consultas múltiples para el mismo campo, serán
combinados con | demasiado, así que no necesitas para preocuparse sobre aquel.
200
Capítulo 8

Así como el campo, el elemento de filtro puede tener un atributo de contexto cuyo contenido
será fusionado con el contexto actual y eventual otros atributos de contexto en la vista de
búsqueda. Esto es esencial para vistas que agrupación de soporte (ve recetas sobre kanban y
graph vistas), porque el contexto resultante determina el campo(s) para ser agrupado por con el
grupo clave_por. Miraremos a los detalles de agrupar en las recetas apropiadas, pero el
contexto tiene otros usos también. Por ejemplo, puedes esconder las columnas que dependen
de un valor de contexto por poner el atributo invisible del elemento de campo en la vista de
lista a algo como el siguiente:
Invisible="no contexto.Consigue( esqué_col1')"

Puedes utilizar un filtro para cambiar esta columna encima o fuera. O podrías escribir
un campo de función que regresos los valores diferentes que dependen de el contexto,
entonces puedes cambiar los valores por activar un filtro.
La búsqueda se ve también responde a context llaves. En una manera muy similar a default
valores cuándo creando registros, puedes pasar defaults para una vista de búsqueda vía el
contexto. Si habíamos puesto un contexto de { earch_default_proveedor': 1} en nuestra
acción anterior, el filtro de proveedores habría sido preselected en la vista de búsqueda. Esto
trabaja sólo si el filtro tiene un nombre aun así, el cual es por qué tú tener que siempre puesto lo.
Para poner defaults para campos en la vista de búsqueda, uso
Búsqueda_default_$fieldname.

Más allá, el campo y los elementos de filtro pueden tener unos grupos property con el mismo
semantics cuando en las vistas de forma para hacer el elemento sólo visible para grupos
seguros.

Ve también
Para detalles aproximadamente manipulando el contexto, ver la receta que Pasa
parámetros a formas y acciones: Contexto.

Cambiando existiendo views: herencia de


Vista
Hasta ahora, ignoramos las vistas de existir y declaró completamente nuevo unos.
Mientras esto es didactically sensato, raramente serás en situaciones donde quieres
definir una vista nueva para un modelo de existir. Qué bastante querrás hacer es a
ligeramente modificar las vistas de existir, serlo a sencillamente tiene muestre un campo
añadiste al modelo en vuestro addon, o para personalizarlo a vuestras necesidades o
vuestro cliente es.
En esta receta, cambiaremos el default forma de socio para mostrar el registro último
modification fecha y también deja buscar que. Entonces también mostraremos esta columna en
los socios' vista de lista.
201
Backend Vistas

Cómo para hacerlo...


1. Inyectar el campo en el default vista de forma:
<Récord id="modelo_de forma_de socio" de
vista="ir.ui.Modelo"> <de nombre de campo="de
vista">res.Campo</de socio>
<Nombre de campo="hereda_id" ref="base.Campo_de forma_de
socio" /> <de vista tipo="de arco" del nombre="xml">
<Posición de sitio web="de nombre" de
campo="después de que"> <nombre de
campo="escribe_fecha" />
</Campo>
</Campo>
</Récord>

2. Añadir el campo al default vista de búsqueda:


<Récord id="vista_res_modelo_de filtro" del
socio="ir.ui.Modelo"> <de nombre de campo="de
vista">res.Campo</de socio>
<Nombre de campo="hereda_id" ref="base.Vista_res_nombre_de
campo" /> <de filtro de socio="tipo" de arco="xml">
<xpath expr="." Nombre="de campo">
<de interior de
posición="escribe_fecha" />
</xpath>
</Campo>
</Récord>

3. Añadir el campo al default vista de lista:


<Récord id="modelo_de árbol_de socio" de
vista="ir.ui.Modelo"> <de nombre de campo="de
vista">res.Campo</de socio>
<Nombre de campo="hereda_id" ref="base.Campo_de árbol_de
socio" /> <de vista tipo="de arco" del nombre="xml">
<Posición de email="de nombre" de
campo="antes de que"> <nombre de
campo="escribe_fecha" />
</Campo>
</Campo>
</Récord>

Después de actualizar vuestro módulo, tendrías que ver el campo extra Último actualizado
encima debajo el campo de sitio web en la forma de socio. Cuándo escribes en something
aquello parece una fecha (un dígito o dos) en la caja de búsqueda, tenga que proponer para
buscar socios último modificados en esta fecha, y en la vista de lista del socio, tendrías que
ver la fecha de modificación dejó de la columna de email.
202
Capítulo 8

Cómo trabaja...
El campo crucial aquí es, cuando probablemente has adivinado, hereda_id. Necesitas
pasarlo el XML ID de la vista quieres modificar (hereda de), y el campo de arco entonces
contiene instrucciones encima cómo para modificar el existiendo XML ingenio de nodoshin la
vista estás heredando de.
De hecho tendrías que pensar del proceso entero tan XML bastante sencillo
procesamiento, porque todas las partes semánticas vienen sólo mucho más tarde.
El más canonic instrucción dentro del campo de arco de una vista heredada es el elemento
de campo, el cual tiene el requerido atribuye nombre y posición . Porque puedes tener cada
campo sólo una vez en una forma, el nombre ya singularmente identifica un campo, y con el
atributo de posición, podemos colocar cualquier cosa pusimos dentro del elemento de
campo tampoco antes de que (1), interior (2), o después de que (3) el campo
nombramos. El default es interior, pero para readability siempre tendrías que nombrar la
posición significas. Recuerda que no estamos hablando semantics aquí; esto es sobre la
posición en el pariente de árbol del XML al field hemos nombrado. Cómo esto será rendered
después es un asunto completamente diferente.
Ejemplo 2 encima demuestra una aproximación diferente. El xpath el elemento selecciona
el primer elemento que empareja el XPath la expresión nombrada en el atributo expr.
También, aquí el atributo de posición dice el procesador dónde para poner el xpath
los contenidos del elemento.

XPath Podría mirar un poco scary, pero es un medio muy eficaz de seleccionar el nodo
necesitas trabajar encima. Tomar el tiempo para mirar a través de algunas expresiones
sencillas, eswor th lo. Probablemente en el tutorials encontrarás, tú tropezón al nodo de
contexto del plazo a qué algunas expresiones es relativo. En Odoo herencia de vista, aquello
es siempre el elemento de raíz de la vista estás heredando de.

Para todo los otros elementos encontrados en el campo de arco de una vista de
heredar, el procesador busca el primer elemento con el mismo nombre de nodo y
emparejando atributos (con la posición de atributo excluyó, cuando esto es parte de la
instrucción). Uso esto sólo en casos donde es muy improbable que esta combinación no
es única, como un elemento de grupo combinado con un atributo de nombre.

Nota que te puede tener tan muchos elementos de instrucción


dentro del campo de arco cuando necesitas. Sólo utilizamos uno
por vista heredada porque hay no más actualmente queremos
cambio.

Allí ha más...
El atributo de posición tiene dos otros valores posibles: reemplaza y atributos . Utilizando
reemplaza causa el elemento seleccionado para ser reemplazado con el contenido del
elemento de instrucción. Consiguientemente, si no tienes cualquier content, el elemento
seleccionado es sencillamente sacó.
En la lista o vista de forma encima causarían el campo de email para ser sacado.

<Posición de email="de nombre" de campo="reemplaza" />

203
Backend Vistas

Sacando los campos pueden causar otras vistas de heredar


para romper y several de modo parecido efectos de lado feo,
así que evita que si es posible. Si te realmente necesidad de
sacar campos, así que en un ver cuál viene tarde por orden de
evaluación (ve próximo).

Utilizando los atributos tiene un muy diferentes semantics de todo del encima. El
procesador eln espera el elemento para contener los elementos de atributo con un
atributo de nombre. Aquellos elementos entonces soler atributos de conjunto en el
elemento seleccionado. Si quieres heed el aviso de arriba, tú mejor puesto el atributo
invisible a 1 para el email campo:
<Posición de email="de nombre" de
campo="nombre"> <de atributo de los
atributos="invisible">1</atributo>
</Campo>

Orden de evaluación en herencia de vista


Porque hemos sólo una vista de padre y uno heredando vista, nosotros no corridos a cualesquier
problemas con chocar vista overrides. Cuándo has instalado un par de módulos, encontrarás
mucho overrides para la forma de socio. Esto es todo bien mientras cambian cosas diferentes en
una vista, pero hay ocasiones donde es importante de entender cómo el overriding trabajos
Para evitar conflictos. Los descendientes directos de una vista están evaluados en orden
ascendente de su campo de prioridad, tan las vistas con una prioridad más baja están aplicadas
primero. Cada paso de herencia está aplicado al resultado del primero, así que si una vista con
prioridad 3 cambios un campo y otro con prioridad 5 lo saca, las cosas son bien, pero rompen si
las prioridades están invertidas.
Entonces también puedes heredar de una vista que se es una vista de heredar. En este caso, el
segundo nivel que hereda la vista está aplicada al resultado de la vista hereda de. Tan, si tienes
cuatro vistas Un, B, C, y D, donde Un es un standalone forma, B y C hereda de Un, y D hereda de B,
el orden de evaluación es Un, B, D, C. Uso esto para aplicar un orden sin teniendo que confiar en
prioridades; aquello es más seguro en general. Especialmente si algunos heredando la vista
añade un campo y tú necesitan aplicar cambios a este campo, hereda de la vista de heredar y no
del standalone un.

Esta clase de herencia siempre trabajos en el árbol de XML


completo de la vista original, con modificaciones del anteriores
heredando las vistas aplicaron.
204
Capítulo 8

Ve también
Para heredar vistas, un muy útiles y no muy bien el campo sabido es grupos _id. Esta causa de
campos la herencia para tener lugar sólo si el usuario que pide la vista de padre es miembro de
uno de los grupos mencionó allí. Esto te puede salvar mucho trabajo cuándo adaptando la
interfaz de usuario para niveles diferentes de acceso, porque con herencia puedes have
operaciones más complejas que justo mostrando o no mostrando los elementos basaron encima
afiliación de grupo, cuando es posible con los grupos atribuyen encima elementos de forma
como discutidos más tempranos. Por ejemplo puedes sacar elementos si el usuario es miembro
de algún grupo (which es el inverse de qué el atributo de grupos ), pero también algunos
bastante elaborar a trucos les gustan añadir los atributos basó encima afiliación de grupo,
piensa sobre a cosas sencillas les gusta hacer un campo leído sólo para grupos seguros, o más
interesantes a unos les gusta utilizar different widgets para grupos diferentes.

Qué estuvo descrito aquí es el caso si el campo de modo de la vista original está puesto a
primario, mientras las vistas de heredar tienen extensión de modo, el cual es el default.
Miraremos al caso que modo de un heredando view está puesto a primario más tarde, donde
las reglas son ligeramente diferentes.

Documento-formas de estilo
En esta receta, revisaremos algunas directrices de diseño para presentes una experiencia de
usuario uniforme.

Cómo para hacerlo...


1. Inicio vuestra forma con un elemento de encabezamiento:
<header>
<Nombre de botón="_algo_con_el_registro"
Cuerda=" algo" escribe="clase" de objeto="oe_
punto destacado" />
<Nombre de botón="_algo_más" cuerda="Segundo estado" />
<de nombre de campo="de acción" widget="statusbar" />
</Encabezamiento>

2. Entonces añadir un elemento de hoja para contienda:


<Hoja>

3. Puesto algún campo prominente(s) primero:


<div Clase="oe_dejó
oe_etiqueta"> <de título
para="nombre" />
<h1>
<Nombre de
nombre="del campo" />
</h1>
</div>

205
Backend Vistas

4. Pone botones que enlace a los recursos pertinentes para el objeto en su caja propia (if
aplicable):
<div Clase="oe_correcto oe_botones_de nombre" de
caja="de botón"> <nombre de
botón="abre_algo_interesante"
La cuerda="Abre algunos enlazaron clase"
de objeto="de tipo"
récord="oe_stat_botón" />

5. Añadir vuestro contenido, posiblemente dentro de una libreta si hay mucho fields:
<Nombre de
grupo="algún_campo"> <de
nombre de campo="de
campos1" /> <nombre de
campo="campo2" />
</Grupo>

6. Después de la hoja, añadir el chatter widget (si aplicable):


</Hoja>
<div Clase="oe_chatter">
<Seguidor de mensaje="de nombre_de campo_ids" widget="campo_de
seguidores"/> <del correo name="mensaje_ids" widget="hilo_de
correo"/>
</div>

Cómo trabaja...
El encabezamiento tendría que contener botones que ejecuta acciones en el objeto el
usuario actualmente ve. Uso el oe_clase de punto destacado para hacer los botones
visually destacar (aquello es brillante azul en el time de escribir), el cual es una manera
buena de guiar el usuario que considera cuál sería la acción más lógica para ejecutar en el
momento. Prueba tener todo el destacó botones a la izquierda del no-destacó botones y
esconder los botones no pertinentes en el current estado (si aplicable). Si el modelo tiene un
estado, espectáculo él en el encabezamiento que utiliza el statusbar widget. Esto será
rendered bien alineado en el encabezamiento.
El elemento de hoja es rendered como la hoja estilizada y la mayoría de campos importantes
tendrían que ser el primer thing el usuario ve cuándo mirando en él. Uso el oe_título y
oe_dejó clases para tenerles rendered en un sitio prominente (flotando dejado con fuente
ajustada ligeramente medidas en el tiempo de escribir).
Si hay otros registros de interés respecto del récord el usuario actualmente ve (como las
facturas del socio en una forma de socio), puesto les en un elemento con el oe_correcto y
oe_Clases_de caja del botón; esto alinea los botones en él a la derecha. En los botones
ellos, uso el oe_stat_clase de botón para aplicar un uniforme rendering de los botones.
Incluso en caso tú no así diseño, aferrarse a el elemento y nombres de clase
describieron aquí, y ajustar qué necesitas con CSS y posiblemente
Javascript. Esto hará la interfaz de usuario más compatible con el existiendo
addons y dejarte para integrar mejor con el núcleo addons.

206
Capítulo 8

Elementos de forma dinámica que utilizan


attrs
Tan lejos, sólo hemos mirado a cambiar las formas que dependen de los grupos del usuario (el
atributo de grupos en elementos y los grupos_id el campo encima heredó vistas), pero nada
más. Esta receta te mostrará cómo para cambiar las formas basaron en el contenido de algunos
campos en él.

Cómo para hacerlo...


1. Definir un atributo attrs encima algún elemento de forma:
<Padre de nombre="del campo_id"
attrs="{'Invisible': [('es_compañía', '=', Cierto)],
esquired': [('es_compañía', '=', Falso)]}" />

2. Cuida que todos los campos refieres a es disponible en vuestra forma:


<Nombre de campo="es compañía_" invisible="Cierto" />

Esto hará el padre de campo_id invisible si el socio es una compañía , unnd requirió si
no es una compañía.

Cómo trabaja...
El attrs el atributo contiene un diccionario con las llaves invisibles, requeridos, y
readonly (todo de ellos opcionales). Los valores son ámbitos que puede referir a los
campos que existen en la forma (y realmente only aquellos, así que ningún camino
salpicado), y el diccionario entero está evaluado según las reglas para Pitón de lado del
cliente describieron más tempranas. Tan por ejemplo, puedes acceder el contexto en el
operando de mano correcto.

Allí ha más...
Mientras este mecanismo es bastante straightforward para los campos escalares, es
menos obvio cómo para manejar el2muchos y muchos2muchos campos. De hecho, en
estándar Odoo puedes no mucho con aquellos campos dentro de un attrs atributo.
Pero si sólo necesitas comprobar si tal campo es vacío o no, nose [[6, Falso, []]]
como vuestro operando de mano correcto.

Embedded Vistas
Cuándo muestras un un2muchos o un muchos2mucho campo en una forma, no tienes mucho
control encima cómo es rendered hasta ahora si no has utilizado uno del especializado widgets.
También, en el caso de muchos2un campos, es deseable a veces para ser capaz de influir la
manera el registro enlazado está abierto. En esta receta, miraremos a cómo para definir vistas
privadas para aquellos campos.

207
Backend Vistas

Cómo para hacerlo...


1. Definir vuestro campo como usual, pero no cierra la etiqueta:
<Niño de nombre="del campo_ids">

2. Sencillamente escribir la definición de vista(s) a la etiqueta:


<Árbol>
<Campo de nombre="de
nombre" /> <de campo
nombre="de campo" />
<de email de
nombre="teléfono" />
</Árbol>
<Forma>
<Grupo>
<Campo de nombre="de
nombre" /> <de campo
función="de nombre" />
</Grupo>
</Forma>

3. Cercano la etiqueta:
</Campo>

Cómo trabaja...
Cuándo Odoo carga una forma, él primero controles para campos de referencia si hay
vistas embedded tan perfilados anteriormente. Aquellos embedded las vistas pueden
tener los elementos mismos exactos como vistas definimos before. Sólo si Odoo no
encuentra un embedded vista de algún tipo, utilice el modelo default vista de este tipo.

Allí ha más...
Mientras embedded las vistas parecen como una característica grande en primer lugar,
complican herencia de vista mucho. Por ejemplo, cuandotan encima tan embedded las
vistas están implicadas, los nombres de campo no son guaranteed para ser únicos y
normalmente tendrás que utilizar algunos bastante elaborar XPaths para seleccionar
elementos dentro de un embedded vista.
Tan, en general, tienes que mejor sirvió definir el standalone vistas y utilizar la vista
de forma_de las llaves_ref y vista_de árbol_ref describió más temprano.
208
Capítulo 8

Kanban Vistas
Hasta ahora, hemos presentado el usuario con una lista de registros que puede ser abierto
para mostrar una forma. Mientras aquellas listas son eficaces cuándo presenting mucha
información, tienden para ser bastante atenuar dado la carencia de posibilidades de
diseño. En esta receta, tendremos una mirada en kanban vistas, los cuales nos dejamos
a listas presentes de registros en un más apelando manera.

Cómo para hacerlo...


1. Definir una vista de type kanban:
<Récord id="kanban_todo_modelo" de
clientes="ir.ui.Modelo"> <de nombre de campo="de
vista">res.Campo</de socio>
<Tipo de arco="de nombre" de
campo="xml"> <kanban>

2. Lista los campos vas a utilizar en vuestra vista:


<Campo de nombre="de
nombre" /> <de campo
proveedor="de nombre" />
<Cliente de nombre="del campo" />

3. Algún diseño:
<Plantillas>
<t t-Nombre="kanban-cajas">
<div
Clase="oe_kanban_tarjeta"
> <un tipo="abierto">
<Nombre de nombre="del campo" />
</Un>
<t t-
Si="récord.Proveedor.Valor_crudo
o récord.Cliente.Valor_crudo">
Es
<t t-
Si="récord.Cliente.Valor_crudo">
un cliente
<t t-
Si="récord.Proveedor.
Valor_crudo"> y /t.
<>
</t>
<t t-
Si="récord.Proveedor.Valor_crudo
"> un proveedor
</t>
</t>
</div>
</t>
</Plantillas>

209
Backend Vistas

4. Cercano todas las etiquetas:


</kanban>
</Campo>
</Récord>

5. Añadir esta vista a uno de vuestras acciones. Esto queda como un ejercicio para el
lector.

Cómo trabaja...
Necesitamos dar una lista de campos para cargar en (2) para ser capaces de accederles
más tarde. El contenido del elemento de plantillas tiene que ser un solo t elemento con
el attribute t-nombrar puesto al valor kanban-cajas.
Qué escribes dentro de este elemento será repetido para cada registro, con especial
semantics para el t elementos y el t-* atributos. Para detalles aproximadamente que,
refiere a Capítulo 15, Desarrollo de Cliente de la Web, y el recipe lado de Cliente QWeb
porque, técnicamente, kanban las vistas son una repetición de QWeb plantillas.
Hay unas cuantas modificaciones qué es extraño a kanban vistas. Tienes acceso al caso
de variables, modo_único_leído, registro, y widget . Los campos pueden ser
accessed por utilizar registro.fieldname, El cual es un objeto con el valor de
propiedades y valor_crudo , donde el valor es el campo valor formatted en una
manera presentable al usuario y el valor_crudo es el valor del campo cuando proviene
la base de datos.

Muchos2muchos campos make una excepción aquí. Sólo


conseguirás un id lista vía la variable récord. Para un usuario
representación legible, tienes que utilizar el elemento de
campo.

Nota el atributo de tipo del enlace en la parte superior de la plantilla. Estas marcas de
atributo Odoo generar un enlace que obolígrafos el registro en el modo de vista (abierto) o en el
editar modo (edita), o elimina el registro (elimina). El atributo de tipo también puede ser
objeto o acción , el cual render enlaces que llamada una función del modelo o una acción. En
ambos casos, necesitas a supplement los atributos para los botones en forma ve tan
perfilados más tempranos. En vez del un elemento, también puedes utilizar el elemento de
botón; el atributo de tipo ha igual semantics allí.

Allí ha más...
hay unos cuantos más helper valor de funciones que menciona. Yof necesitas generar un
pseudo-color aleatorio para algún elemento, uso la función
kanban_color(algunos_variables), el cual regresará un CSS clase que conjuntos el
de fondo y propiedades de color. Esto es normalmente utilizado en el t-att-
elementos de clase.
210
Chapter 8

Si quieres mostrar una imagen almacenada en un campo binario, uso


kanban_imagen(modelname, fieldname, record.id.Valor_crudo), el cual regresa
un dato URI si incluiste el campo en vuestra lista de campos y el campo está puesto, un
placeholder si el campo no es set, o un URL que marcas Odoo corriente los contenidos del
campo si no incluiste él en vuestra lista de campos. No incluye el campo en la lista de campos
si necesitas mostrar muchos registros simultáneamente o esperas imágenes muy grandes.
Normalmente, utilizarías esto en un t-att-src atributo de un img elemento.
Para campos de texto de longitud arbitrarios, considera utilizar
kanban_texto_ellipsis(yourstring, medida), el cual cultivos la cuerda a la medida
dada y añade un ellipsis (...).

Espectáculo kanban tarjetas en columnas


según su state
Esta receta te muestras cómo a setup un kanban vista donde el usuario puede arrastrar y caer un
registro de una columna al otro, así empujando el récord en cuestión a otro estado.

Preparándose
Ahora y en el resto de este capítulo, haremos uso del módulo de proyecto aquí cuando define
modelos que los deja mejores de datar y el estado basó vistas que los definidos en el módulo de
base. Tan antes procediendo, añade proyecto a la lista de dependencias de vuestro addon.

Cómo para hacerlo...


1. Definir un kanban view para tareas:
<Récord id="kanban_modelo" de
tareas="ir.ui.Modelo"> <de nombre de
campo="de vista">proyecto.Nombre</de campo>
<de campo de tarea="tipo" de arco="xml">
<kanban
default_Grupo_por="escenificar_i
d"> <etapa de nombre="del
campo_id" />
<Plantillas de
nombre="de nombre"
/> <de campo>
<t t-Nombre="kanban-cajas">
<div
Clase="oe_kanban_nombre">
<de nombre de campo="de
tarjeta" />
</div>
</t>
</Plantillas>
</kanban>
</Campo>
</Récord>

2. Añadir una carta y una acción que utiliza esta vista. Esto queda como un ejercicio para el
lector.

211
Backend Vistas

Cómo trabaja...
Kanban views Agrupación de soporte, el cual te dejas para mostrar registros que tiene el
campo de grupo en común en la misma columna. Esto es generalmente utilizado para un
estatal o etapa_id campo, porque deja el usuario para cambiar el valor de este campo
para un registro por sencillamente arrastrando él a otra columna. Pone el atributo
default_grupo_por en el kanban elemento al nombre del campo quieres grupo por
para uso de marca de esta funcionalidad.

Allí ha más...
Si no definido en el atributo dedicado, cualquier filtro de búsqueda puede undd agrupación
por poner una llave de contexto grupo nombrado_por al nombre de campo(s) para agrupar
por.

Vistas de calendario
Estos paseos de receta tú a través de cómo para mostrar y editar información sobre fechas
y duraciones en vuestros registros en una manera visual.

Cómo para hacerlo...


1. Definir una vista de calendario:
<Récord id="modelo_de tarea_de proyecto" de
calendario="ir.ui.Modelo"> <de nombre de campo="de
vista">proyecto.Campo</de tarea>
<Tipo de arco="de nombre" de campo="xml">
<Fecha de inicio_de fecha="de calendario_fecha" de
parón_de fecha="de inicio_proyecto" de
color="del fin_id">
<Campo de nombre="de
nombre" /> <de campo
usuario="de nombre_id" />
</Calendario>
</Campo>
</Récord>

2. Añade las cartas y las acciones que utilizan esta vista. Esto queda como un ejercicio para
el lector.

Cómo trabaja...
Las necesidades de vista del calendario para ser nombres de campo pasado en el inicio de
fecha_de los atributos y parón_de fecha para indicar which campos para mirar en
cuándo construyendo la representación visual. Campos de uso de escribir Datetime
cuando todo más te conseguirá resultados extraños. Mientras inicio_de fecha está
requerido, puedes dejar fuera parón_de fecha y poner el retraso de fecha_del
atributo en cambio, el cual está esperado para ser un campo de Flotador que
representa la duración en horas.

212
Capítulo 8

La vista de calendario te dejas para dar graba cuáles tienen el mismo valor en un campo igual
(Arbitrariamente asignado) color. Para utilizar esta funcionalidad, puesto el color de
atributo al nombre del campo necesitas. En nuestro ejemplo, podemos ver en uno mira
qué tareas pertenecen al mismo proyecto, porque asignamos proyecto_id como el
campo para determinar los grupos de color.
Los campos nombras en el cuerpo del elemento de calendario está mostrado ingeniohin el
bloque que representa el intervalo de tiempo cubrió, separado por comas.

Allí ha más...
La vista de calendario tiene algunos otros atributos útiles. Si quieres entradas de calendario
abierto en un popup en vez de la vista de forma estándar, acontecimiento de
conjunto_abierto_popup a 1 . Si quieres ser capaz de crear una entrada nueva por
justo rellenando algún texto, puesto rápidamente_añadir a 1 . Internamente, esto llama
el nombre del modelo_crea función a de hecho crear el registro.

Si vuestro modelo tiene una idea de cubrir un día entero, puesto todo_día a un field
nombre que es cierto si las cubiertas récord el día entero, y falso otherwise.
En caso necesitas más bien grained control sobre el texto mostrado dentro de los
elementos de calendario, puestos la exhibición de atributo a una cuerda de formato
que utiliza nombres de campo en paréntesis. En our caso, podríamos decir
exhibición="[nombre] (asignado a [usuario_id])" para tener una
representación más verbosa del cual la tarea está asignada a quien.

Nota que esta receta información contenida sobre un tipo de vista del legado gantt, el
cual ha sido obsoleted durante escribir y estuvo sacado del texto.

Graph Y vistas de pivote


En esta receta, tendremos una mirada en Odoo vistas de inteligencia empresarial.
Estos están leídos sólo ve significado a dato presente.

Preparándose
Todavía estamos haciendo uso del módulo de proyecto aquí. Primero, necesitamos alguna
configuración. Activar el checkbox Dirige valoración de tiempo en tareas en Encuadres | de
Configuración y también instalar el proyecto de módulo_timesheet para ser capaz de grabar algún
tiempo en tareas diferentes.

Ahora crear algunos proyecta significados para ser proyectos de paraguas para los clientes.
Entonces, crear un par de tareas para cada proyecto de cliente. Están significados a
modelo actividades diferentes tienes por cliente. Asigna directores diferentes a estos
proyectos y activar las tareas de Uso de la caja. Finalmente, crear tareas ent hese
proyectos, dar una valoración de tiempo por tarea, y escribir algunas horas de trabajo en
estas tareas.
213
Backend Vistas

Cómo para hacerlo...


1. Definir un graph la vista que utiliza barras:
<Récord id="graph_modelo_de barra_de tarea" de
proyecto="ir.ui.Modelo"> <de nombre de campo="de
vista">proyecto.Campo</de tarea>
<Tipo de arco="de nombre" de
campo="xml"> <graph
barra="de tipo">
<Proyecto de nombre="del campo_id"
nombre="de campo" /> <de fila de
tipo="usuario_id" fila="de tipo" />
<Nombre de campo="medida_de tipo" de
horas="eficaz" /> </graph>
</Campo>
</Récord>

2. Definir un graph la vista que utiliza mesa de pivotes:


<Récord id="graph_modelo_de pivote_de tarea" de
proyecto="ir.ui.Modelo"> <de nombre de campo="de
vista">proyecto.Campo</de tarea>
<Tipo de arco="de nombre" de
campo="xml"> <graph
pivote="de tipo">
<Padre de nombre="del campo_id"
nombre="de campo" /> <de fila de
tipo="usuario_id" fila="de tipo" />
<Nombre de campo="hora_previstas" nombre="de
campo" /> <de medida de tipo="medida_de tipo"
de horas="eficaz" />
</graph>
</Campo>
</Récord>

3. Añade las cartas y las acciones que utilizan esta vista. Esto queda como un ejercicio para
el lector.

Si todo fue bien, tendrías que ver graphs aquello te muestras quéhombre y las horas estuvieron
trabajadas por cliente (los proyectos definimos) bajo la responsabilidad de los directores de
proyecto diferentes.

Cómo trabaja...
El atributo de tipo determina el modo inicial de un graph vista. Los valores posibles son
pivote , barra, línea, y gráfico , mientras la barra es el default. El graph la vista es altamente
interactiva, así que el usuario puede cambiar entre los modos diferentes y también añadir y
sacar campos.

214
Capítulo 8

Los elementos de campo dicen Odoo qué para mostrar en qué eje. Para todo el graphmodo s,
necesitas al menos un campo con fila de tipo y uno con medida de tipo para ver cualquier cosa
útil. Los campos de fila de tipo determinan la agrupación, mientras posiciones de medida del tipo
para el valor(s) para ser mostrado.
Línea graphs soporte único un campo de cada tipo, mientras gráficos y mango de barras dos
campos de grupo con uno miden amablemente. La mesa de pivote apoya una cantidad
arbitraria de grupo y campos de medida. Ninguna preocupación, las cosas no rompen si
cambias a un modo que no apoya la cantidad de grupos y medidas definiste. Es justo que
ignorarán algunos de los campos y no siempre mostrar un resultado muy interesante.

Allí ha más...
Para todo el graph tipos, el Datetime los campos son delicados para agrupar, porque
raramente encontrarás el mismo valor de campo aquí. Tan si tienes un Datetime campo
de fila de tipo, también especificar el atributo de intervalo con uno de los valores
siguientes: día, semana, mes, trimestre, o año . Esto causará la agrupación para tener lugar
en el intervalo dado.
La mesa de pivote también apoya agrupar en columns. Tipo de uso col para los campos
quieres haber allí.

Agrupación, gusta ordenar, confía fuertemente en PostgreSQL. Tan aquí


también la regla aplica que un campo tiene que vivir en la base de
datos y en la mesa actual para ser utilizable.
Es práctica común a dela base de datos buena ve aquello recoge todo
el dato necesitas y definir un modelo arriba de esta vista para tener
todos los campos necesarios disponibles.
Dependiendo de la complejidad de vuestra vista y la agrupación,
construyendo el graph puede ser bastante un caro exercise. Considera
poner la búsqueda de coche_del atributo a Falso en aquellos
casos, de modo que el usuario primero puede ajustar todos los
parámetros y sólo después provocar una búsqueda.

QWeb Informes
La última parte de la capa de presentación está imprimiendo fuera de informes. En
caso has no cultivar ahora, instala wkhtmltopdf tan descrito en Capítulo 1,
Instalando el Odoo Entorno de Desarrollo otherwise no conseguirás reluciente PDFs
cuando resultado de vuestros esfuerzos.

Preparándose
El mecanismo de conversión a PDFs está implementado en el addon informe, así que lo
tendrías que añadir tan dependencia de vuestro addon. También control doble que el
parámetro de configuración
Web.Base.url (O alternativamente, informe.url) Es un URL accesible de vuestro Odoo
caso, otherwise generación de informe toma las edades y el resultado mira divertidosny.

215
Backend Vistas

Cómo para hacerlo...


1. Definir una vista para vuestro informe:
<Plantilla id="qweb_res_cumpleaños_de
socio"> <t t-informe="de
llamada.html_Contenedor">
<t t-Informe="de
llamada.Diseño_interno"> <div
página="de clase">
<hLos cumpleaños de 2>Socio</h2>
<div t-foLogra="docs" t-tan="o" fila="de clase mt4
mb4"> <div clase="col-md-6"><t t-esc="o.name"
/></div> <div clase="col-md-6">
<t t-Si="o.birthdate" t-esc="o.birthdate" />
<t t-Si="no o.birthdate">-</t>
</div>
</div>
</div>
</t>
</t>
</Plantilla>

2. Uso esta vista en una etiqueta de informe:


<Informe id="informa_res_nombre_de
cumpleaños" del
socio="ch08.qweb_res_Modelo_de
cumpleaños" del socio="res.Informe" de
Cumpleaños="de cuerda" de
socio_tipo="qweb-pdf" />

Ahora cuándo abriendo una forma de socio o seleccionando socios en la vista de lista,
tendrías que seroffe rojo para imprimir la lista de cumpleaños.

Cómo trabaja...
En vez de utilizar la sintaxis récord cuando nosotros más tempranos, utilizamos el elemento
de plantilla aquí. Esto es enteramente para comodidad; QWeb las vistas son vistas justas
cuando todo el otros. La razón para utilizar este elemento es que el campo de arco de QWeb las
vistas tiene que seguir reglas bastante estrictas y el elemento de plantilla cuida para generar
un arco contenta cuál cumple estas reglas.

No se preocupa sobre la sintaxis dentro del elemento de plantilla ahora. Este tema será
dirigido extensoly en la receta QWeb en Capítulo 14, Desarrollo de Sitio web del CMS.
216
Capítulo 8

El elemento de informe es otro atajo para una acción de tipo


ir.Acciones.Informe.xml Y un registro de pegamento de tipo ir.Valor. La parte
crucial aquí es que pusiste el name campo al XML completo ID de la vista definiste,
otherwise la generación de informe fallará. El atributo de modelo determina en qué tipo de
récord el informe opera, y el atributo de cuerda es el nombre mostrado al usuario en la
carta de impresión.
Por puestoting tipo_de informe a qweb-pdf , pedimos que el HTML generó por nuestra
vista está corrida a través de wkhtmltopdf para entregar un PDF al usuario. Hay un par de
otro (mayoritariamente deprecated) elecciones, pero en algunos casos, qweb-html puede
ser conveniente a justor ender el HTML dentro del navegador.

Allí ha más...
Hay algunas clases de marcador en HTML de un informe aquello es crucial para el diseño. Ser
seguro para envolver todo vuestro contenido en un elemento con el conjunto de página de
la clase. Si olvidas que, verás nada en absoluto. To Añade un encabezamiento o footer a
vuestro registro, uso el encabezamiento de clase o footer .
También recordar que esto es HTML , así que uso de marca de CSS atributos como
página-rotura-antes de que, página-rotura-después de que, y página-
rotura-interior .
Habrás notado que todo de nuestro cuerpo de plantilla está envuelto en dos elementos con el
t-conjunto de atributo de la llamada. Examinaremos la mecánica de este atributo más tarde,
pero es crucial que te
Hacer igual en vuestros informes. Estos elementos cuidan que el HTML generó enlaces a todo
el necesarios CSS archiva und contiene algunos otro dato necesitado para la generación de
informe.
Mientras html_el contenedor no realmente tiene una alternativa, el segundo t-la
llamada también podría ser informe.Diseño_externo. La diferencia es que el diseño
externo ya viene con un encabezamiento y footer mostrando el logotipo de compañía, el
nombre de la compañía, y algunos otra información esperas de la comunicación externa de
una compañía, mientras el diseño interno justo te das un encabezamiento con paginación, la
fecha de impresión, y el nombre de la compañía. Por el bien de consistency, siempre utilizar
uno del dos.

Nota que informe.Diseño_interno, informe.Diseño_externo,


informe.Encabezamiento_de diseño_externo, e
informe.Diseño_ externo_footer (el últimos dos se apellidan por el
diseño externo) es
Vistas justas por ellos, y tú already saber cómo para cambiarles por
herencia. Para heredar con el elemento de plantilla, uso el atributo
hereda_id.
217
9
Dato de
módulo
En este capítulo, cubriremos los temas siguientes:

f Utilizando externo IDs y namespaces


f Cargando el dato que utiliza XML
f
archivos
Utilizando el noupdate y forcecreate las
f
banderas que Cargan el dato que utiliza
f
CSV archivos
f
Cargando el dato que utiliza YAML
archivos
Addon Actualizaciones y migración de
dato

En ordena no para tener que repetir mucho código, haremos uso de los modelos defined en
Capítulo 4,
Modelos de aplicación. Tan para seguir los ejemplos, grab el código de este capítulo.

Introducción
En este capítulo, miraremos en cómo addons puede proporcionar dato en tiempo de
instalación. Esto es útil para proporcionar default valores y añadiéndometadata como
descripciones de vista, cartas, o acciones. Otro uso importante está proporcionando dato de
manifestación, el cual está cargado cuándo la base de datos está creado con el dato de
manifestación de la Carga checkbox activó.

Utilizando externo IDs y namespaces


Había mucha charla aproximadamente XML IDs ya, sin especificar lo que un XML ID es.
Esta receta dará un más profundo entendiendo de este.

219
Dato de módulo

Cómo para hacerlo...


Escribimos a ya existiendo registros de demostrar cómo para utilizar módulo de cruz
references:

1. Añadir un archivo de dato a vuestro módulo manifiesta:


'Dato': [
'dato/res_socio.xml',
],

2. Cambio el nombre de nuestra compañía principal:


<Récord id="base.Modelo_de compañía"
principal="res.Nombre"> <de nombre de campo="de
compañía">Packt publicando</campo>
</Récord>

3. Pone nuestro principal company socio cuando editor:


<Récord id="biblioteca_de modelo" de recetario="de libro.Libro">
<Editor de nombre="del campo_id" ref="base.Registro_de
socio" /> </principal>

Encima instalación de este módulo, la compañía será rebautizada y el libro de la receta


próxima será asignado a nuestro socio. En actualizaciones subsiguientes de nuestro
módulo, sólo el editor será asignado, pero el nombre de la compañía quedará
untouched.

Cómo trabaja...
Un XML ID es una cuerda que refiere a un registro en la base de datos. El IDs ellos es
registros de modelo ir.Modelo.Dato. Las filas de esta mesa contienen el que declaran
módulo ID, la cuerda de identificador, el modelo referido, y el referido ID. Cada vez un ID
tiene que ser mirado arriba, Odoo controles si la cuerda es namespaced ya (aquello es,
contiene exactamente un punto), y si no añade el nombre de módulo actual como
namespace. Entonces mira arriba si hay ya un registro en ir.Modelo.Dato con el nombre
especificado. Si tan, una declaración de ACTUALIZACIÓN para el listó los campos está
ejecutado; si no, un CREAR la declaración está ejecutada. Este is por qué puedes dar dato
parcial cuándo un récord ya existe, cuando nosotros encima.

Una aplicación extendida para dato parcial, aparte de cambiar los registros
definieron por otros módulos, está utilizando un elemento de atajo para
crear un registro en una manera conveniente y escribiendo un campo en
este récord cuál no es apoyado por el elemento de atajo:
<Ventana_de acto id="mi_acción" nombra="Mi
modelo" de acción="res.Socio"
/>
<Récord id="mi_modelo" de
acción="ir.Acciones.Nombre_de campo"> <de ventana
de acto="búsqueda_de coche" eval="Falso" />
</Récord>

220
Capítulo 9

El ref función, cuando utilizó abajo en la receta que Carga el dato que utiliza XML
archivos, también añade el módulo actual como namespace si apropiado, pero levanta un
error si el XML resultante ID no existe ya. Esto también aplica al id atributo si it no es
namespaced ya.

Allí ha más...
Probablemente necesitas acceder registros con un XML ID de vuestro código tarde o
temprano. Uso la función self.env.ref() En aquellos casos, el cual regresa un explorar
récord del referenced registro. Nota que aquí, te unlways tiene que pasar el XML lleno ID.

Ve también
Consultar la receta que Utiliza el noupdate y forcecreate banderas para descubrir por qué
el nombre de la compañía está cambiado sólo encima instalación del módulo.

Cargando el dato que utiliza XML archivos


Utilizando Capítulo 4, Modelo de Aplicacións modelo de dato, añadiremos un libro y un
autor cuando dato de manifestación, mientras añadimos un editor bien sabido como dato
normal en nuestro módulo.

Cómo para hacerlo...


Crea dos XML archivos y enlazarles en vuestro __openerp__.py Manifiesta archivo:

1. Añade en un archivo dato llamado/demo.xml A vuestro manifestar, en el demo sección:


'demo': [
'Dato/demo.xml',
],

2. Añade contenido a este archivo:


<odoo>
<Récord id="autor_af" modelo="res.Nombre"> <de
nombre de campo="de socio">Alexandre
Fayolle</campo>
</Récord>
<Récord id="autor_dr" modelo="res.partner">
<Nombre de nombre="del campo">Daniel
Reis</campo>
</Récord>
<Récord id="autor_hb" modelo="res.Nombre">
<de nombre de campo="de socio">Holger
Brunn</campo>
</Récord>
<Récord id="biblioteca_de modelo" de
recetario="de libro.Nombre"> <de nombre de
campo="de libro">Odoo nombre</de campo> <de
campo de Recetario="short_campo">de
recetario</del nombre>

221
Dato de módulo
<Liberación de fecha="de nombre_de campo">2016-03-
01</campo>
<Autor de nombre="del campo_ids" eval="[(6, 0,
[ref('autor_af'), ref('autor_dr'),
ref('autor_hb')])]" />
<Editor de nombre="del campo_id"
ref="res_socio_packt" /> </registro>
</odoo>

3. Añadir un archivo dato llamado/res_socio.xml A vuestro manifestar, en la sección


de dato:
'Dato': [
'dato/res_socio.xml',
],

4. Añade contenido a este archivo:


<odoo>
<Récord id="res_socio_packt" modelo="res.Nombre">
<de nombre de campo="de socio">Packt
Publishing</ciudad> <de nombre de campo="de
campo">Birmingham</campo>
<País de nombre="del campo_id"
ref="base.uk" /> </récord>
</odoo>

Cuándo actualizas vuestro módulo ahora, verás de todas formas el editor creamos, y, si
vuestra base de datos ha demo el dato habilitó, cuando señalado out en Capítulo 1,
Instalando el el Odoo Entorno de Desarrollo, también encontrarás este libro y sus autores.

Cómo trabaja...
Cuando has visto encima, demo el dato es técnicamente justo igual dato tan normal. La
diferencia única es que el primero está estirado por el demo llave en el manifestar, el último por
la llave de dato.

Para crear un registro, uso el elemento récord, el cual tiene los atributos obligatorios id
y modelo . Para el id atributo, consultar la receta que Utiliza externo IDs y
namespaces; el atributo de modelo refiere to la propiedad de nombre de _un modelo.
Entonces utilizas el elemento de campo para llenar columnas en la base de datos cuando
definido por el modelo nombraste. El modelo también decide cuáles son los campos
obligatorios para llenar y también posiblemente define default valores, en qué caso tú no
need para dar aquellos campos un valor explícitamente.
Cuando mostrado encima, el elemento de campo puede contener su valor como texto sencillo en
caso de valores escalares.

Para instalar referencias, hay dos posibilidades. El más sencillo está utilizando el ref atributo, el
cual trabaja para muchos2un campos y justo contiene el XML ID del récord de ser referenced.
222
Capítulo 9

Para uno2muchos y muchos2muchos campos, necesitamos recurrir a el eval atributo. Esto


es un atributo de propósito general que puede soler evaluar Pitón coda para utilizar como el
valor del campo - pensar de strftime('%Y-01-01') como un ejemplo - para poblar un campo de
fecha. X2muchos campos esperan ser poblados por una lista de 3-tuples, donde el primer
valor del tuple determina la operación para ser llevada a cabo. Dentro de un eval atributo,
tenemos el acceso a una función llamó ref, el cual regresa la base de datos ID de un XML
ID dado como cuerda. Esto nos dejo para referir a un registro sin saber su hormigón ID, el
cual es probablemente diferente por base de datos, cuando explicado en el following:
f (2, id, Falso) elimina el registro enlazado con id de la base de datos, el
tercer elemento del tuple está ignorado.
f (3, id, Falso) sólo corta el enlace a un registro con id , pero deja el
existiendo récord cuando es. Aquí también, ell ast elemento del tuple está
ignorado.
f
(4, id, Falso) añade un enlace al existiendo récord id, el último elemento del tuple
está ignorado también. Esto tendría que ser qué utilizas la mayoría del tiempo,
normalmente acompañado por utilizar el ref función para conseguir la base de datos ID
f
de un récord sabido por su XML ID.
(5, Falso, Falso) trabajos únicos para muchos2muchos campos y corta
f
todos los enlaces, pero mantiene el enlazado graba intacto.
(6, Falso, [id, …]) trabajos únicos para muchos2muchos campos y
primero aclara fuera actualmente referenced registros de reemplazarles con los
mencionados en la lista de IDs. El segundo elemento del tuple está ignorado.

Nota que asuntos de orden en archivos de datos y que registros dentro


de archivos de datos sólo pueden referir a los registros definieron en los
datos archiva más tempranos en la lista. Esto es por qué tú siempre
tendría que comprobar si vuestro módulo instala en una base de datos
vacía, porque durante desarrollo, a menudo pasa que añades registros
por todas partes el sitio, el cual trabaja porque los registros definieron
después es ya en la base de datos de una actualización anterior.
Demo data Es siempre cargado después de los archivos de la llave
de dato, el cual es por qué la referencia en los trabajos de ejemplo.

Allí ha más...
Mientras puedes hacer básicamente cualquier cosa con el elemento récord, hay elementos
de atajo definió aquello lo hace más conveniente parath e desarrollador para crear clases
seguras de registros.
Los ejemplos son menuitem, plantilla o ventana de acto. Refiere a Capítulo 8, Backend
Vistas y
Capítulo 14, Desarrollo de Sitio web del CMS para información sobre aquellos.

Un elemento de campo también puede contener el elemento de función, el cual llama una
función definida en un modelo para proporcionar el valor de un campo. Ver la receta que Utiliza
el noupdate y forcecreate banderas para una aplicación donde sencillamente llamamos una
función a directamente escribir a la base de datos, circumventing el mecanismo de cargar.

223
Dato de módulo

El encima la lista pierde fuera de entradas para 0 y 1 , porque no son muy útiles cuándo
cargando dato. Están introducidos como sigue por el bien de completeness:
f(0, Falso, {'llave': valor})crea un registro nuevo del referenced
modelo,with sus campos llenaron del diccionario en posición tres. El segundo
elemento del tuple está ignorado. Cuando aquellos registros no tienen un XML ID y está
evaluado cada vez el módulo está actualizado, dirigiendo para plegar entradas, es
mejor en general para evitar this, crear el registro en su elemento récord propio, y
enlazarlo cuando será explicado más tarde.
f(1, id, {'llave': valor})puede soler escribir en un existiendo registro
enlazado.Para las mismas razones tan encima, tendrías que evitar esta
sintaxis.
Utilizarás ambos de ellos extensively en Capítulo 5, Lado de Servidor Básico Lógica
Empresarial.

Utilizando el noupdate y forcecreate


banderas
La mayoría de addons tiene tipos diferentes de datos. Algún dato sencillamente necesita
existir para el módulo para trabajar correctamente, otro dato tiene que no incluso ser
cambiado por el noser, mientras la mayoría de dato está significado para ser cambiado por
el placer del usuario y es sólo proporcionado como comodidad. Esta receta detallará cómo
para dirigir los tipos diferentes. Primero, escribiremos un campo en un ya existiendo
registro, entonces, crearemos un récord aquello está supuesto para ser recreado durante
una actualización de módulo.

Cómo para hacerlo...


Podemos aplicar comportamientos diferentes de Odoo cuándo cargando dato por poner
atributos seguros en el encerrando odoo elemento o el elemento récord él.
1. Añadir un editor sólo creó unt tiempo de instalación, pero no actualizado en
actualizaciones subsiguientes. Aun así, si el usuario lo elimina, sea recreado:
<odoo noupdate="1">
<Récord id="res_socio_packt" modelo="res.Nombre">
<de nombre de campo="de socio">Packt
publicando</campo>
</Récord>
</odoo>

2. Anunciod una categoría de libro que no es cambiado durante addon actualizaciones


y no recreados si el usuario lo elimina:
<odoo noupdate="1">
<Récord id="categoría_de libro_toda" biblioteca="de
modelo.Libro.Categoría" forcecreate="falso">
<Nombre de campo="nombra">Todo
registro</de campo> </de los libros>
</odoo>

224
Capítulo 9

Cómo trabaja...
El odoo el elemento puede tener un noupdate atributo, el cual está propagado al
ir.Modelo.El dato graba creado cuándo leyendo los registros de dato cerrados por primera
vez, acabando como columna en esta mesa.
When Odoo Instala un addon (llamado init modo), todo noupdate los registros están
escritos. Cuándo actualizas un addon (modo de actualización llamada), existiendo XML
IDs está comprobado para ver si tienen el noupdate conjunto de bandera, y si tan,
elementos intentando escribir a este XML ID es ignored. Esto no es el caso si el récord en
cuestión estuvo eliminado por el usuario, el cual es por qué tú puede forzar no recreando
noupdate registros también en modo de actualización por poner la bandera forcecreate en
el récord a falso .

En legado addons (<= 8.0), a menudo encontrarás un openerp el elemento


que encierra un elemento de dato y sólo allí récord y otros elementos. Esto
es todavía posible, pero deprecated. Por ahora, odoo, openerp, y datos
haber exactamente el mismo semantics, están significados como
paréntesis para encerrar XML datos.

Allí ha more...
Puedes forzar init modo por empezar vuestro Odoo servidor con el parámetro --
init=vuestro_addon, de este modo overwriting todo existiendo noupdate registros. Esto
también la causa eliminó registros de ser recreados. Nota que esto puede causar registros dobles
y errores de instalación relacionada si un módulo circumvents el XML ID mecanismo, por ejemplo,
por crear registros en código de Pitón llamado por
YAML Archivos.

Para módulos escribes de arañazo, no necesitas para preocuparse demasiado sobre noupdate
registros en cualquier vuestro propios addon or otro unos, mientras sólo lo instalas después de
todo desarrollo
Está hecho. Pero imaginar añades una característica nueva a un módulo de existir que es
ya fuera en el salvaje. Entonces podrías necesitar poner un valor concreto encima, por
ejemplo, el socio principal, el cual es un noupdate registro. Para usuarios con una versión
anterior ya instalada, esta actualización de dato nunca será ejecutada! Puedes trabajar
alrededor esto por utilizar el elemento de función a temporalmente unset el récord a
noupdate, como sigue:
<Nombre de función="escribe"
modelo="ir.Modelo.Búsqueda"> <de nombre de
función="de dato" modelo="ir.Modelo.Dato">
<Valor eval="[( soyodule', '=', 'base'), ('nombre', '=',
soyain_ socio')]" />
</Función>
<Valor eval="{'noupdate': función}"
/> </Falsa>
<Récord id="base.Modelo_de socio" principal="res.Socio">
<field Libro="de nombre_ids" eval="[(4,
ref('recetario_de libro'))]" </registro>

225
Dato de módulo
<Nombre de función="escribe"
modelo="ir.Modelo.Búsqueda"> <de nombre de
función="de dato" modelo="ir.Modelo.Dato">
<Valor eval="[( soyodule', '=', 'base'), ('nombre', '=',
soyain_ socio')]" />
</Función>
<Valor eval="{'noupdate': función}"
/> </Cierta>

Con este código, puedes circumvent cualquier noupdate bandera, pero ser seguro esto es
realmente qué quieres.
Otra opción para solucionar el escenario sketched aquí es para escribir un guión de
migración, tan fueratachado en la receta siguiente.

Ve también
Odoo También utiliza XML IDs para mantener pista del cual los datos es para ser eliminados
después de un addon actualización. Si un registro tuvo un XML ID del módulo namespace
antes de la actualización, pero el XML ID no es restablecido durante el update, el récord y su
XML ID será eliminado de la base de datos porque están considerados obsoletos. Para una
discusión más profunda de este mecanismo, ver la receta siguiente: Addon actualizaciones
y migración de dato.

Cargando el dato que utiliza CSV archivos


Mientras puedes hacer nuncaything necesitas con XML archivos, este formato no es el
más conveniente cuándo necesitas proporcionar cantidades más grandes de datos,
especialmente dados que muchas personas son más cómodas preprocessing dato en Calc,
o algunos otro spreadsheet software. Otra ventaja de este formato es que es qué
consigues cuándo tú utiliza la función de exportación estándar. En esta receta, tendremos
una mirada en mesa importadora-gustar dato.

Cómo para hacerlo...


Tradicionalmente, listas de control del acceso (ACLs), (refiere a Capítulo 10, Seguridad de
Acceso) es un tipo de datos que está cargado vía CSV archivos:

1. Añade seguridad/ir.Modelo.Acceso.csv A vuestros archivos de dato:


'Dato': [

Esecurity/ir.Modelo.Acceso.csv',
],

2. Añadir un ACL para nuestros libros en este archivo:


"id","nombre","modelo_id:id","grupo_id:id","perm_leído"
, "perm_escribe","perm_crea","perm_unlink"
"Usuario_de libro_de biblioteca_de acceso","ACL para
libros", "libro_de biblioteca_del
modelo","base.Usuario_de grupo",1,0,0,0

226
Capítulo 9

Ahora tenemos un ACL que permisos usuarios normales para leer registros de libro, pero no
les deja para editar, crea o delete les.

Cómo trabaja...
Sencillamente caes todos vuestros archivos de dato en vuestro manifestar es lista de dato.
Odoo Utilizará la extensión de archivo para decidir qué tipo de archiva es. Una especialidad
de CSV los archivos es que su nombre de archivo tiene que emparejar el nombre del modelo
para ser imported, en nuestro caso, ir.Modelo.Acceso. Las primeras necesidades de línea
para ser un encabezamiento con columna nombra que partido los nombres de campo del
modelo exactamente.
Para valores escalares, puedes utilizar un citado (si es necesario porque la cuerda
contiene cita o comas él) o un unquoted cuerda.
Cuándo escribiendo muchos2un campos con un CSV archivo, Odoo primero intenta
interpretar el valor de columna como un XML ID: Si no hay ningún punto, añadir el nombre
de módulo actual como namespace, lookup el resultado enir.Modelo.Dato. En caso esto
falla, el nombre del modelo_search la función se apellida con el valor de la columna como
el parámetro y el primer resultado regresaron gana. Cuándo este también falla, la línea está
considerada nula y Odoo levanta un error.

Nota que el dato leído de CSV los archivos es siempre


noupdate=Falsos y hay no manera conveniente alrededor de este. Esto
significa actualizaciones subsiguientes de vuestro addon siempre
overwrite los cambios posibles hicieron por el usuario.

Allí ha más...
Importador un2muchos y muchos2muchos campos con CSV los archivos es posibles, pero un
poco delicados. En general, estás apostadoter fuera creando los registros por separado e
instalando la relación con un
Archivo de XML después, o trabajando con un segundo CSV archivo que instala la relación.

Si te realmente necesidad de crear relacionada graba dentro del mismo archivo, orden vuestras
columnas tantha t todos los campos escalares son a la izquierda y los campos del modelo
enlazado son a la derecha, con un encabezamiento de columna que consta de el nombre del
campo de enlazar y el campo del modelo enlazado, separado por un colon:
"id","nombre","modelo_id:id","perm_leído","perm_leído",
"grupo_id:nombre", "usuario_de libro_de biblioteca_de acceso","ACL
para libros","libro_de biblioteca_del modelo",1,"mi grupo"

Esto crearía un grupo llamó mi grupo, podrías escribir más campos en el registro de grupo
por añadir columnas a la derecha. Si necesitas enlazar registros múltiples, repetir la línea y
sólo cambiar las columnas de mano correctas como apropiados. Dado que Odoo llena
columnas vacías con el valor de la línea anterior, no necesitas para copiar todos los datos,
pero sencillamente añadir una línea con valores vacíos salvó para los campos del modelo
enlazado quierest o llena.

227
Dato de módulo

Cargando el dato que utiliza YAML archivos


Un tercer formato para importación de datos es YAML, el cual te das menos elevado que
XML, pero aún más control que CSV. Tradicionalmente, esté utilizado para pruebas más que
para importación de datos, el cual is por qué tienes más posibilidades para llamar código
aquí.

Cómo para hacerlo...


Tomar los pasos siguientes para traducir la primera receta en este capítulo a YAML:

1. Añade en un archivo dato llamado/demo.yml A vuestro manifestar, en el demo


sección:
'demo': [
'Dato/demo.yml',
],

2. Añade contenido a este archivo:


-
!Récord {id: autor_af, modelo: res.Nombre}
de socio: Alexandre Fayolle
-
!Récord {id: autor_dr, modelo: res.Nombre}
de socio: Daniel Reis
-
!Récord {id: autor_hb, modelo: res.Nombre}
de socio: Holger Brunn
-
!Récord {id: bovale_recetario, modelo:
biblioteca.Nombre} de libro: Odoo recetario
Nombre_corto: liberación
de fecha_del recetario:
2016-03-01
Autor_ids: [(6, 0, [ref('autor_af'), ref('autor_dr'),
ref('Autor_hb')])]
editor_id: res_socio_packt

3. Añadir un archivo dato llamado/res_socio.yml to Vuestro manifestar, en la sección


de dato:
'Dato': [
'dato/res_socio.yml',
],

4. Añade contenido a este archivo:


-
!Récord {id: res_socio_packt, modelo: res.Nombre} de
socio: Packt publicando
Ciudad: Birmingham
país_id: base.uk
228
Capítulo 9

Nosotros el mismo tan en la primera receta, pero en YAML sintaxis. Nota que YAML los
archivos necesitan la extensión .yml Para ser reconocido correctamente.

Cómo trabaja...
Odoo Introduce un YAML datatype registro, el cual es donde la mayoría del Odoo-
el comportamiento concreto está implementado. Cuando con XML, unas
necesidades récord un ID y un modelo puesto para algo útil.
Para valores de campo, utilizas YAML notación estándar, el cual significa no necesitas citando para
cuerdas. Cuándo llenando muchos2un campos, Odoo sencillamente presupondrá aquello qué das
aquí es un
XML ID, tan no hay ninguna necesidad para extra marcando aquí tampoco.

Allí ha más...
Hemos visto que enlazando un2muchos y muchos2muchos campos es un poco incómodos
con XML y CSV, y en el ejemplo encima, utilizamos la misma sintaxis para hacer el enlazando.
En YAML, lo podrías haber hecho más elegantemente por sencillamente escribiendo el
siguiente:
-
!Récord {id: recetario_de libro, modelo:
biblioteca.Nombre} de libro: Odoo recetario
Nombre_corto: liberación
de fecha_del recetario:
2016-03-01 autor_ids:
- Nombre: Alexandre Fayolle
- Nombre: Daniel Reis
- Nombre: Holger Brunn

De este modo, creaste tres registros de tipo res.Socio, enlazado en el autor de campo_ids.
Nota que aquí también, creando registros inline significa tienen ningún XML ID, el cual lo
hace difícil de referir a ellos de otros sitios.

Ve también
Esta receta focused encima utilizando YAML archivos para cargar dato. Si estás interesado
en probar utilizando YAML archivos, refiere a Capítulo 7, Depurando y Testaje Automatizado.

Addon Actualizaciones y migración de dato


El modelo de dato escoges cuándo escribiendo un addon podría resultar para tener algunos
weaknesses, así que puedes necesitar ajustar él durante el ciclo de vida de vuestro addon.
Para dejar que sin muchos tajos, Odoo apoya versioning en addons y corriendo migraciones si
es necesario.
229
Dato de módulo

Cómo para hacerlo...


Suponemos que en una versión más temprana de nuestro módulo, el campo_de liberación
de la fecha era un campo de carácter , donde las personas escribieron cualquier cosa
vieron cabidos como la fecha. Ahora nos damos cuenta necesitamos este campo para
comparaciones y agregaciones, el cual es por qué nosotros quiere cambiar su tipo para
Datar. Odoo Un trabajo grande en conversiones de tipo, pero, en este caso, somos en
nuestro propios, el cual es por qué nosotros necesita proporcionar instrucciones encima
cómo para transformar una base de datos con la versión anterior de nuestro módulo
instalado a una base de datos donde la versión actual puede correr:

1. Bump La versión en vuestro __openerp__.py Manifiesta:


'Versión': '9.0.1.0.1',

2. Proporciona pre-código de migración en migraciones/9.0.1.0.1/pre-


migrate.py:
def Emigra(cr, versión):
cr.Ejecuta('ALTERAR libro de biblioteca_de la MESA
REBAUTIZA liberación de fecha_de la COLUMNA
para datar_liberación_char')

3. Proporciona código de migración del correo en migraciones/9.0.1.0.1/post-


migrate.py:
De openerp campos de
importación de datetime
fecha de importación

def Emigra(cr, versión):


cr.Ejecuta( esELECTO id, liberación_de fecha_char DE libro_de
biblioteca') para récord_id, fecha_vieja en cr.fetchall():
# Control si el campo pasa para ser puesto en Odoo interno
# Formato
Fecha_nueva =
Ninguno
prueba:
Campos_de fecha =
nueva.Fecha.De_cuerda(fecha_vieja) exceptúa:
Si len(fecha_vieja) == 4 y fecha_vieja.isdigit():
# Probablemente un año
Fecha_de fecha =
nueva(int(fecha_vieja), 1, 1) más:
# Prueba algunos separators, juego con año/de
mes/del día
# Orden
# ...
Si fecha_nueva:
cr.Ejecuta('libro de biblioteca_de la ACTUALIZACIÓN
PONE liberación_de fecha=%s',
(Fecha_nueva,))

Sin este código, Odoo habría rebautizado la columna de liberación_de fecha vieja para
datar_la liberación_ movida y creó un nuevo un, porque hay no conversión automática de
campos de carácter para datar campos. Del punto de vista del usuario, el dato en
liberación_de fecha sencillamente sería ida.
230
Capítulo 9

Cómo trabaja...
El primer punto capital es que aumentas el version número de vuestro addon, cuando las
migraciones corridas sólo entre versiones diferentes. Durante cada actualización, Odoo escribe
el número de versión del manifestar en el tiempo de la actualización a la mesa ir_módulo_de
módulo. El número de versión está prefijado con Odoo versión importante y menor, si el
número de versión tiene tres
O menos componentes. En el ejemplo encima, nosotros explícitamente también nombrados
Odoo versión importante y menor, el cual es práctica buena , pero un valor de 1.0.1 habría
tenido el mismo efecto, porque, internamente, Odoo prefixes números de versión corta para
addons con su versión importante y menor propia número. Generalmente, utilizando la
notación larga es una cosa buena porque puedes ver con justo una mirada en el manifestar
archivo para qué versión de Odoo un addon está significado.
El dos migration los archivos son código justo archiva aquello no necesita para ser
registrado anywhere. Cuándo actualizando un addon, Odoo compara el addon versión
cuando notado en ir_módulo_de módulo con la versión en el addon es manifiesta. Si
el manifestar es la versión es más alta (después de que posiblemente undding Odoo
versión importante y menor), este addon carpeta de migraciones será buscada si
contiene carpetas con la versión(s) en entre, hasta, e incluyendo la versión que es
actualmente actualizó.
Entonces, dentro de las carpetas encontradas, busca Python archivos cuyo inicio de
nombres con pre- , les carga, y les espera para definir una función llamó emigrar, el cual
tiene dos parámetros. Esta función se apellida con un cursor de base de datos como el
primer argumento y la versión actualmente instalada como el segundo argumento. Esto
pasa antes de Odoo incluso miradas en el resto del código el addon define, así que puedes
suponer nada cambiado en vuestro diseño de base de datos comparó a la versión anterior.
Después de todo pre-emigrar las funciones corridas exitosamente, Odoo carga los
modelos y dato declared en el addon, los cuales pueden causar cambios en el diseño de
base de datos. Dado rebautizamos liberación_de fecha en pre-migrate.py, Odoo justo
creará una columna nueva con aquel nombre, pero con el tipo de dato correcto.

Después de que aquello, con el mismo algoritmo de búsqueda, correo-migrcomió los


archivos serán buscados y ejecutados si encontrados. En nuestro caso, necesitamos mirar
en cada valor y ver si podemos hacer algo utilizable fuera de él, otherwise, mantenemos
NULL tan dato. No escribe los guiones que iteran sobre una mesa entera tú si no
absolutamente necessary; en este caso, tendríamos que haber escrito un SQL ilegible muy
grande cambio que hace qué queremos.

Si sencillamente quieres rebautizar una columna, no necesitas un


guión de migración. En este caso, puedes poner el oldname
parámetro del campo en cuestión al nombre de columna vieja del
campo, Odoo entonces cuida del rebautizando él.
231
Dato de módulo

Allí ha más...
En ambos el pre- y correo-pasos de migración, sólo tienes acceso a un cursor, el cual no es
muy conveniente si estás utilizado a Odoo environments. Pueda dirigir a resultados
inesperados para utilizar modelos al llegar a este punto, porque en el pre- paso, el addon
los modelos no son todavía cargados y también, en el correo- paso, los modelos definieron
por addons dependiendo de el actuales addon no es todavía cargado también. Pero si this
no es un problema para ti, tampoco porque quieres utilizar un modelo vuestro addon no
toca o un modelo para qué sabes el antedicho no es un problema, puedes crear el entorno
estás utilizado a por escribir el siguiente:
De openerp importación SUPERUSER_ID
de openerp.api Entorno de importación

def Emigra(cr, versión):


env = Entorno(cr, SUPERUSER_ID, {})
# env Aguanta todo actualmente modelos cargados

Ve también
Cuándo escribiendo guiones de migración, a menudo serás afrontado con tareas repetitivas
como checrey si una columna o la mesa existe, rebautizando cosas, o mapeo algunos valores
viejos a valores nuevos. Está frustrando y error-prone para reinventar la rueda aquí; considera
utilizar https://github. com/OCA/openupgradelib Si puedes proporcionar la
dependencia extra.
232
10
Seguridad de
acceso
En este capítulo, veremos cómo a:

f Crea grupos de seguridad y asignar them a los


f usuarios Añaden acceso de seguridad a
f modelos
f Acceso de límite a campos en modelos
f Límite el acceso récord que utiliza
seguridad de Uso de reglas récord
grupo para activar características

Para concisely conseguir el punto a través de, las recetas en esta marca de capítulo
adiciones pequeñas a un módulo de existir. Escogimos utilizar el módulo creado por las
recetas en Capítulo 3, Creando Odoo Módulos. A mejor seguir los ejemplos aquí, tendrías
que tener aquel módulo creado y a punto para utilizar.

Crea grupos de seguridad y asignarles a


usuarios
Seguridad unccess en Odoo está configurado a través de grupos de seguridad: los
permisos están dados a grupos y entonces los grupos están asignados a usuarios. Cada
área funcional tiene seguridad de base agrupa proporcionada por una aplicación
central.
Cuándo el addon los módulos extienden un existiendo applicatión, tendrían que añadir
permisos a los grupos correspondientes, cuando mostrados en el Añadir acceso de
seguridad a receta de modelos más tarde.
Cuándo el addon los módulos añaden una área funcional nueva, no todavía cubierto por un
existiendo aplicación central, tendrían que añadir el corresponding grupos de seguridad.
Normalmente, tenemos que haber al menos el usuario y funciones de director.
Tomando el ejemplo de Biblioteca introdujimos en Capítulo 3, Creando Odoo Módulos, no
cabe pulcramente en cualquier del Odoo aplicaciones de núcleo, así que añadimos los
grupos de seguridad para él.
233
Seguridad de acceso

Preparándose
Esta receta supone tienes un caso a punto, con el mi_módulo disponible, cuando descrito
en Capítulo 3, Creando Odoo Módulos.

Cómo para hacerlo...


Para añadir grupos de seguridad de acceso nuevos a un módulo, actuar los pasos siguientes:

1. Marca seguro que el addon el módulo manifiesta __openerp__.py Tiene la llave


de categoría definió:
'Categoría': 'Biblioteca',

2. Añadir la seguridad de biblioteca/de_seguridad nueva.xml Archivo al


manifestar llave de dato:
'Dato': [ esecurity/seguridad_de
biblioteca.xml', 'biblioteca/de
vistas_book.xml',
],

3. Añadir el archivo de XML nuevo para los registros de dato en seguridad/de


biblioteca_de la seguridad.xml, empezando con una estructura vacía:
<?xml Versión="1.0" codificando="utf-
8"?> <odoo>
<Dato noupdate="0">
<!-- Registros de datos van
aquí --> </datos>
</odoo>

4. Añade dentro del dato XML elemento las etiquetas récord para los dos grupos
nuevos:
<Récord id="modelo_de usuario_de biblioteca" de
grupo="res.Nombre"> <de nombre de campo="de
grupos">campo</de Usuario>
<Categoría de nombre="del campo_id"
ref="base.Biblioteca_de categoría_del
módulo"/>
<Nombre de campo="implicó_ids"
eval="[(4, ref('base.groArriba_usuario'))]"/>
</Récord>

<Récord id="modelo_de director_de biblioteca" de


grupo="res.Nombre"> <de nombre de campo="de
grupos">campo</de Director>
<Categoría de nombre="del campo_id"
ref="base.Biblioteca_de categoría_ del módulo"/>
<Nombre de campo="implicó_ids" eval="[(4,
ref('usuario_de biblioteca_ del grupo'))]"/>
<field Usuarios="de nombre" eval="[(4, ref('base.Raíz_de
usuario'))]"/> </registro>
234
Capítulo 10

Si nosotros upgrade el addon módulo, estos dos registros serán cargados y seremos
capaces de verles en los Usuarios de Encuadres de opción | de carta | Grupos:

How Trabaja...
Addon Los módulos están organizados en áreas funcionales, o aplicaciones importantes,
como Finanza & de Contabilidad, Ventas, o Recursos Humanos. Estos están definidos por
la llave de categoría en el manifestar archivo.

Si un nombre de categoría no existe todavía, seaun utomatically creó. Para comodidad, una
base.Categoría_de categoría_<del módulo> XML ID también será generado para
el nombre de categoría nuevo en lowercase letras, reemplazando espacios con
underscores. Esto es útil de relacionar grupos de seguridad con categorías de aplicación.
En nuestro ejemplo, utilizamos el nombre de categoría de la Biblioteca, y genere una
base.Biblioteca_ de categoría_del módulo XML identificador.

Evita utilizar no-ASCII caracteres en el nombre de categoría, pero si


tú , marca seguro para utilizar un unicode cuerda. Por ejemplo:
u'Biblioteca'.

Por convention, el dato archiva añadir la seguridad relacionó los elementos tendrían
que ser colocados dentro de un subdirectorio de seguridad.
El orden en qué los archivos está declarado en el atributo de dato es importante, desde
entonces no puedes utilizar un identificador antes de que ha sido definido. Podemos
whormiga para utilizar referencias en vistas para los grupos de seguridad habíamos
definido, así que es más para colocar el archivo de dato de la seguridad en la parte
superior de la lista antes del ACL archivos de definición y la otra interfaz de usuario archivos
de dato.
235
Seguridad de acceso

Seguridad groups tendría que ser añadido utilizando un archivo de XML. Pueda añadir
registros que queremos ser customizable por los usuarios de fin. Para impedir aquellos
cambios posibles que son perdidos en un módulo upgrade, tendríamos que añadir
aquellos registros dentro de un <dato noupdate="1"> elemento. Esto es normalmente
el caso para seguridad reglas récord, hablados en el Límite el acceso récord que utiliza
receta de reglas récord más tarde.
Pero para grupos de seguridad, la práctica utilizada en Odoo núcleo addon los módulos es
para tenerles definido dentro de un <dato noupdate="0"> elemento. Esto significa que
they será reescrito en un módulo upgrade, y así que no tendría que ser directamente
personalizó. Customization En cambio tendría que ser hecho por crear grupos nuevos que
hereda del default unos.

Los grupos están almacenados en el res.Modelo de grupos, y sus la mayoría de


columnas importantes son como sigue:

f Nombre: Esto es el grupo nombre de exhibición.


fCategoría_id: Esto es una referencia a la categoría de aplicación, y
sueleorganizar los grupos en la forma de usuarios.
f Implicó_ids: Estos son los otros grupos para heredar permisos de.
fUsuarios: Esto es la lista de los usuarios que pertenecen a este grupo. En el
nuevo addon módulos,normalmente queremos el admin usuario a
oportunamente pertenecer al grupo de director de la aplicación.
El primer grupo de seguridad utiliza tan implicado_ids la base.Usuario_de grupo . Esto
es el employee usuario, y es la seguridad básica agrupa todo el backend los usuarios están
esperados para compartir.
El segundo grupo de seguridad pone un valor en el campo de usuarios para asignarlo al
usuario de administrador, aquello tiene la base.Raíz_de usuario XML ID.
Los usuarios que pertenecen a un grupo de seguridad automáticamente pertenecerá a su implicó
grupos. Si Director de Biblioteca ha implicado el grupo de Usuario de la Biblioteca, asignándolo
a un usuario también le incluirá en el
Grupo de Usuario de la biblioteca.

También, los permisos de acceso concedieron por grupos de seguridad son acumulables. Un
usuario tiene algún permiso en cualquier de los grupos pertenece a (directamente o
implicado) concede que permiso.
Algunos grupos de seguridad están mostrados en la forma de usuario como caja de
selección en vez de individual checkboxes. Esto pasa cuándo el implicó los grupos sonen t él
categoría de aplicación misma y es linearly interrelacionado a través de implicado_ids . Por
ejemplo, Grupo Un tiene implicado Grupo B, y Grupo B ha implicado Grupo C.
Nota que las relaciones definieron en los campos de preceder también tienen relaciones
inversas que puede ser editared en el relacionó modelos, como grupos de seguridad y
usuarios.
Poniendo valores encima campos de referencia, como categoría_id e implicado_ids,
está hecho utilizando el relacionado graba XML IDs y algunos sintaxis especial.

236
Capítulo 10

Para Muchos2una relaciones, the ref el atributo suele enlace con el registro con el XML
correspondiente ID. Para Uno2muchos campos, como implicados_ids, el eval el atributo
está utilizado con una lista de tuple órdenes. Por ejemplo, el tuple 4 cuando el primer
elemento añade las referencias en el elemento próximo o elementos. Esta sintaxis está
explicada en detalle en Capítulo 9,
Dato de módulo.

Allí ha más...
También digno de mención es la base especial.Grupo_ningún_un grupo de
seguridad. En el anterior Odoo versiones, esté utilizado para adelantó las características
escondidas por default, y sólo hechos visibles cuándo la bandera de Características
Técnica estuvo activada. Desde entonces versión 9.0 esto ha cambiado, y aquellas
características están hechas visibles mientras el Modo de Desarrollador está activado.
Los permisos de acceso concedieron por grupos de seguridad son acumulables sólo. TAquí
es ninguna manera de negar un acceso dado por algún grupo. Esto significa un grupo
manualmente creado para personalizar los permisos tendrían que heredar del grupo más
cercano con menos permisos que aquellos pretendidos (si cualquier), y entonces añadir
todos los permisos restantes necesitaron.
Los grupos también tienen disponibles estos campos adicionales:

fCartas (elcampo_de accesode la carta): Estos son los elementos de carta el grupo
tiene acceso a fVistas (elcampo_de accesode la vista): Estos son el UI ve el grupo
tiene acceso a
fDerechos de acceso (elacceso_de modelofield): Estos son el acceso
tiene en modelos,detallados en el Añadir acceso de seguridad a receta de
modelos
fReglas (elcampo_de gruposde la regla): Estos son el acceso de nivel récord
gobierna aquello aplica a el grupo, detallado en el Límite el acceso récord que
utiliza reglas récord recipe
f Notas (el campo de comentario): Esto es una descripción o texto de comentario para el
grupo
237
Seguridad de acceso

Añade acceso de seguridad a modelos


Es común para el addon módulos para añadir modelos nuevos. Por ejemplo, en el anterior
chapter tuvimos ejemplos añadiendo un modelo de Libros de Biblioteca nuevo.
Es fácil de perder la creación de acceso de seguridad para los modelos nuevos definió
en un addon módulo si lo pruebas utilizando el conveniente admin usuario, porque
admin bypasses todos los controles de seguridad.

However, modelos sin ACLs provocará un mensaje de registro del aviso encima cargando,
informando sobre el desaparecido ACL definiciones: La biblioteca de modelo.El libro tiene
ninguno reglas de acceso, considera añadir un. Para evitar que, tendrías que mirar para
tales mensajes durante pruebas, y antes de que publishing vuestra marca de código seguro
te corrido las pruebas con el demo usuario más que admin.
Tan, para modelos nuevos para ser utilizables por no-admin usuarios, necesitamos definir
sus listas de control de acceso de seguridad, de modo que Odoo sabe cómo les tenga que
acceder y lo que operations cada grupo de usuario tendría que ser dejado.

Preparándose
Tomaremos el módulo creado en Capítulo 3, Creando Odoo Módulos y añadir a él el
desaparecido ACLs.

Cómo para hacerlo...


Mi_módulo ya tendría que contener los modelos/library_book.py archivo de Pitón
que crea tél biblioteca.Modelo de libro. Ahora añadiremos un archivo de dato que
describe el control de acceso de la seguridad de este modelo por actuar los pasos
siguientes:
1. Editar el __openerp__.py Manifiesta archivo para declarar un archivo de dato nuevo:
Dato: [
# …Grupos de seguridad
ecurity/ir.Modelo.Acceso.csv',
# …Otros archivos de dato
]

2. Añade al módulo una seguridad de archivo


nueva/ir.Modelo.Acceso.csv, con las líneas siguientes:
id,nombre,modelo_id:id,grupo_id:id,perm_leído,perm_escribe,pe
rm_ crea,perm_unlink
Usuario_de libro_de biblioteca_de
acceso,biblioteca.Libro.Usuario,abucheo_de biblioteca_
del modelok,base.Usuario_de grupo,1,0,0,0
Libro_de biblioteca_del
acceso_admin,biblioteca.Libro.admin,libro_de biblioteca_
del modelo,base.Sistema_de grupo,1,1,1,1

238
Capítulo 10

Tenemos que entonces upgrade el módulo para tener estos ACL los registros añadieron a
nuestro Odoo base de datos. Más importantly, si firmamos en a una base de datos de
manifestación que utiliza el demo usuario, tendríamos que ser capaces de acceder la opción
de carta de la Biblioteca sin cualesquier errores de seguridad.

Cómo trabaja...
Las listas de control de acceso de seguridad están almacenadas en el núcleo
ir.Modelo.Modelo de acceso. Justo necesitamos añadir a él los registros que describen los
derechos de acceso pretendidos para cada grupo de usuario.

Cualquier tipo de archivo de datos haría, pero la práctica común es para utilizar un CSV
archivo. El archivo puede ser colocado anywhere dentro del addon directorio de módulo,
pero la convención es para tener all la seguridad relacionó archivos dentro de un
subdirectorio de seguridad.
El primer paso en nuestra receta declara este archivo de dato nuevo al manifestar y el segundo
añade el archivo que describe las reglas de control de acceso de seguridad. El CSV el archivo
tiene que ser nombrado después del modelo where los registros serán cargados, así que el
nombre utilizó no es justo una convención y es obligatorio.

Si el módulo también crea grupos de seguridad nueva, su archivo de dato tendría que ser
declarado antes del ACLs' archivo de dato, desde entonces les puedes querer utilizar para
el ACLs y tan ya tienen que ser creados cuándo el ACL el archivo está procesado.
Las columnas en el CSV el archivo es como sigue:

fid: Esto es el XML ID identificador interno para esta regla. Cualquier nombre
único dentro delmódulo haría, pero la convención es para utilizar
modelo_<de acceso>_<groarriba>.
fNombre: Esto es un título para la regla de acceso y, por convención, la práctica
común esutilizar un acceso.<Modelo>.<Nombre> de grupo.
fModelo_id:id: Esto es el XML ID para el modelo. Odoo Automáticamente asigna
talun ID a modelos con un nombre de modelo_<del formato>, utilizando el
nombre de _el modelo con underscores en vez de puntos. Si el modelo estuvo
creado en un diferente addon módulo, un plenamente cualificado XML ID está
necesitado, incluyendo el nombre de módulo.
fGrupo_id:id: Esto es el XML ID para el grupo de usuario. Si dejó vacío, él applies
a todosusuarios. El módulo de base proporciona algunos grupos básicos,
como base.Usuario_de grupo, para todos los empleados y base.Sistema_de
grupo para el usuario de administración. Otras aplicaciones pueden añadir sus
grupos de usuario propios.
f perm_Leyó: Esto puede leer los registros de modelo (0 o 1).
fperm_Escribe: Esto puede actualizar los registros de
modelo (0 o 1).fperm_Crea: Esto puede añadir registros
de modelo nuevo (0 o 1).fperm_unlink: Esto puede
eliminar registros de modelo (0 o 1).
El CSV archivo utilizamos añade acceso único leído a los Recursos Humanos | Employee
grupo de seguridad estándar, y lleno escribe acceso al grupo | de Encuadres de la
Administración.

239
Seguridad de acceso

El grupo de usuario del Empleado, base.Usuario_de grupo, es particularmente


importante porque los grupos de usuario añadieron por el Odoo las aplicaciones
estándares heredan from lo. Esto significa que si necesitamos un modelo nuevo para ser
accesible por todo el backend usuarios, a toda costa de las aplicaciones concretas
trabajan con, tendríamos que añadir aquel permiso al grupo de Empleado.
El resultante ACLs puede ser visto del GUI en Encuadres | Technical | Lista | de
Controles de Acceso de Seguridad, cuando mostrado en el siguiente screenshot:

Algunas personas lo encuentran más fáciles de utilizar esta interfaz de usuario para
definir ACLs y entonces utilizar la característica de exportación para producir un CSV
archivo.

Allí ha más...
Haga sentido para nosotros para dar este permiso al usuario de Biblioteca y grupos de director
de la Biblioteca definieron en el Crear Grupos de seguridad y asignarles a receta de Usuarios. Si
seguiste que receta, es un ejercicio bueno a entonces seguir este un, adaptando el grupo
identifiers al
Biblioteca unos.

Es importante de notar que el acceso lista proporcionado por el addon los módulos no
tendrían que ser directamente personalizados, desde entonces serán reloaded en el
módulo próximo upgrade, destruyendo cualquier customization que podría haber sido
hecho de the GUI.
240
Capítulo 10

Para personalizar ACLs, dos aproximaciones pueden ser utilizadas. Uno es para crear la
seguridad nueva agrupa aquello hereda del proporcionado por el módulo y añadir permisos
adicionales encima lo, pero esto deja sólo para añadir, no para sacar. Una aproximación
más flexible puede ser a uncheck la bandera Activa a falso en el particular ACL líneas, para
inutilizarles. No es visible por default, así que necesitamos editar la vista de árbol para
añadir el <nombre de campo="columna" /> activa. También podemos añadir nuevos
ACL líneas para añadiritional o permisos de sustitución. En un módulo upgrade, el
deactivated ACLs no será reactivado y el añadido ACL las líneas no serán afectadas.
Es también valor notando que ACLs sólo aplicar a modelos regulares y no necesita para ser
definido para Abstracto o Transi ent modelos. Si definido, estos serán desatendidos y un
mensaje de aviso será provocado al registro de servidor.

Acceso de límite a campos en modelos


En algunos casos podemos necesitar más bien grained control de acceso y para
limitar el acceso a campos concretos en unmo del.
Es posible para un campo para ser accesible sólo por grupos de seguridad concreta,
utilizando el atributo de grupos. Mostraremos cómo para añadir al modelo de Libros de la
Biblioteca un campo con acceso limitado.

Cómo para hacerlo...


Para añadir un campo con acceder limitado a specific grupos de seguridad, actuar los pasos
siguientes:

1. Editar el archivo de modelo para añadir el campo:


Campos_de notas = privadas.Texto(agrupa='base.Sistema_de grupo')

2. Editar la vista en el archivo de XML para añadir el campo:


<Nombre de campo="notas_privadas" />

Aquello es. Ahora upgrade el añadirencima módulo para los cambios en el modelo para
tener lugar. Si firmas en con un usuario sin acceso de configuración del sistema, como
demo en una base de datos con dato de manifestación, la forma de libros de la Biblioteca
no mostrará el campo.

Cómo trabaja...
Campos con el groups el atributo es especialmente manejado para comprobar si el
usuario pertenece a cualquiera de los grupos de seguridad indicó en el atributo, y si no
saca él de UI vistas y ORM operaciones para el usuario.
Nota que esta seguridad no es superficial. El campo no es enly escondido en la interfaz de
usuario, pero es también hecho inutilizable al usuario en el otro ORM operaciones, como
leídos y escribir . Esto es también cierto para el XML-RPC o JSON-RPC llamadas.
241
Seguridad de acceso

Ser prudente cuándo utilizando estos campos en business lógica, o encima cambiar UI
acontecimientos (@api. onchange Métodos); pueden levantar errores para usuarios
sin acceder al campo. Un workaround para este es para utilizar elevación de privilegio,
como el sudo() método de modelo o el computar_sudo atributo de campo para
computó campos.
El valor de grupos es una cuerda conteniendo una coma lista separada de válido XML
IDs para grupos de seguridad. La manera más sencilla de encontrar el XML ID para un
grupo particular es a navigate a su forma, en Grupos | de Usuarios | de los Encuadres, y
entonces acceder la Vista Metaopción de dato del depurar carta, cuando mostrado en el
siguiente screenshot:

Allí ha más...
En algunos casos, necesitamos un campo para ser disponible o no dependiendo de
condiciones particulares, como los valores en un campo particular, gusta etapa_id or
estado. Esto es normalmente manejado en el nivel de vista que utiliza atributos como
estados o attrs , a dinámicamente exhibición o esconder el campo según condiciones
seguras. Puedes referir a Capítulo 8, Backend Vistas para una descripción detallada.
Nota que estos techniques trabajo en el nivel de interfaz del usuario sólo y no proporciona
seguridad de acceso real. Para aquel te tendría que añadir controles en la capa de lógica
empresarial. Cualesquiera añaden métodos de modelo decoraron con @apremia ,
implementando las validaciones concretas pretendieron, o ext acabar el crear, escribe,
o unlink métodos para añadirles lógica de validación. Puedes conseguir más idea encima
cómo para hacer este en Capítulo 5, Lado de Servidor Básico Lógica Empresarial.
242
Capítulo 10

Límite el acceso récord que utiliza reglas


récord
Una necesidad común para una aplicación es para ser capaz de limitar lo que los
registros son disponibles a cada usuario en un modelo concreto.
Esto está conseguido utilizando reglas récord. Una regla récord es una expresión de filtro
del ámbito definido en un modelo que entonces será añadido en cada consulta de dato
hecha por el affected usuarios.
Cuando un ejemplo, añadiremos una regla récord en el modelo de libros de la Biblioteca
de modo que los usuarios en el grupo de empleado sólo tendrá acceso a libros crearon en
la base de datos.

Preparándose
Esta receta supone tienes un caso a punto, con mi_ módulo disponible, cuando descrito en
Capítulo 3, Creando Odoo Módulos.

Cómo para hacerlo...


Las reglas récord están añadidas utilizando un dato XML archivo. Para hacer tan, actuar los
pasos siguientes:

1. Asegura que la seguridad/de biblioteca_de la seguridad.xml El archivo es


referenced por manifestar llave de dato:
'Dato': [ esecurity/seguridad_de
biblioteca.xml',
# ...
],

2. Tendríamos que tener una seguridad/de biblioteca_de la


seguridad.xml Archivo de dato, con una <sección> de dato que crea el grupo
de seguridad. Después de que lo, añadir esta segunda <sección> de dato para
que así conste reglas:
<Dato noupdate="1">
<record Modelo="ir.Regla" id="regla_de usuario_de libro_de
biblioteca"> <Biblioteca de nombre="de nombre">de
campo: ve sólo campo de campo</de libros> <propio
modelo="de nombre_id" ref="campo_de libro_de
biblioteca"/> <de modelo grupos="de nombre" eval="[(4,
ref('base.Grupo_
Usuario'))]"/>
<Fuerza de ámbito="de nombre_de campo">
[('crear_uid', '=', user.id)]</campo>
</Récord>
<Modelo récord="ir.Regla" id="la
biblioteca_reserva_todos_gobiernan"> <Biblioteca
de nombre="de nombre">de campo: ver todo
nombre</de campo> <de campo de libros="modelo_id"
ref="libro_de biblioteca_del modelo"/>

243
Seguridad de acceso

<Grupos de nombre="del campo" eval="[(4,


ref('base.Sistema_ de grupo'))]"/>
<Fuerza de ámbito="de nombre_de campo">[(1,
'=', 1)]</registro> </de campo>
</Dato>

Upgrading El addon el módulo cargará las reglas récord al Odoo caso.

Para mantener la receta sencilla, utilizamos el empleado de núcleo y g de seguridad de los


encuadresroups. En cambio podríamos haber utilizado el usuario de Biblioteca y el director
agrupa tan definidos en el Añadir acceso de seguridad a receta de modelos. Es un ejercicio
bueno para seguirlo y modificar este módulo de modo que utiliza aquellos grupos de
seguridad en cambio.

Cómo trabaja...
Las reglas récord son dato justo graba cargado al ir.Modelo de núcleo de la regla. Mientras el
archivo que les añade podría ser anywhere en el módulo, la convención es para él para ser en el
subdirectorio de seguridad. Es común de tener un archivo de XML solo con ambos grupos de
seguridad y rereglas de cordón.

Grupos diferentes, en los módulos estándares, las reglas récord están cargadas en una sección
de dato con el noupdate="1" atributo. Con este, aquellos registros no serán reloaded en un
módulo upgrade, significando que manual customizations encima les es seguro y wenfermo
sobrevive más tardío upgrades.

Para quedarse compatible con los módulos oficiales, también tendríamos que tener nuestras
reglas récord dentro de un
<Dato noupdate="1"> sección.

Las reglas récord pueden ser vistas del GUI en los Encuadres de opción de la carta |
Seguridad | Técnica | Reglas Récord, cuando mostrados en el siguientes screenshot:
244
Capítulo 10

Siguiente es la regla récord más importante los campos utilizaron en el ejemplo:

f Nombre (nombre) es un título descriptivo para la regla.


f Objeto (modelo_id) es una referencia al modelo la regla aplicó a.
fGrupos (grupos) es la seguridad agrupa que la regla aplica a. Si ninguno, la regla
estáconsiderada global y está aplicado en una manera diferente (más los
detalles siguen más tardíos).
f Definición de regla (ámbito) es una expresión de ámbito con el filtro récord para aplicar.

La primera regla récord creamos era para el grupo de seguridad del Empleado. Utiliza
la expresión de ámbito [('crear_uid', '=', user.id)] para seleccionar sólo
aquellos libros donde el usuario de creación es el usuario actual . Así, sólo serán
capaces de ver los libros crearon por ellos.
Las expresiones de ámbito utilizaron en las reglas récord corridas en el lado de servidor que
utiliza ORM objetos.
Debido a este, notación de punto puede ser utilizada en los campos en el lado izquierdo (el
primer tuple elemento). El correcto side (tercio tuple elemento) es una expresión de Pitón,
evaluado en un contexto habiendo disponible el usuario objeto récord, para el usuario actual,
y la biblioteca de Pitón del tiempo.

Para el grupo de seguridad de los encuadres, lo queremos para ser capaces de ver todos los
libros, independientes de quién les creó en la base de datos. Desde entonces hereda el grupo
de Empleado, a no ser que nosotros algo aproximadamente lo, también sea capaz de ver sólo
los libros crearon por él.
El varios (no global) las reglas récord están unidas juntas utilizando el U operador lógico: cada
regla añade acceso y nunca saca el acceso. Para el Director de Biblioteca para tener acceso a
todos los libros, podemos añadir a él una regla récord para añadir el acceso a libros creó por
otros usuarios, gusta
Esto: [('crear_uid', '!=', user.id)].

Escogimos hacer differently y utilizar la regla especial [(1, '=', 1)] a incondicionalmente dar
acceso a todos los registros de libro. Mientras esto puede parecer redundando, recuerda que
otherwise la regla de usuario de la Biblioteca puede ser personalizada en una manera que
mantendría algunos libros fuera de lograr al
Settings Usuario. Es especial porque el primer elemento de un ámbito tuple tiene que ser
un nombre de campo; este caso exacto es el caso único donde aquello no es cierto.

Las reglas récord están ignoradas para el construidos-en admin


usuario. Cuándo probando vuestras reglas récord, marca seguro
utilizas tanme otro usuario para aquel.

Allí ha más...
Cuándo una regla récord no es asignada a cualquier grupo de seguridad, está
marcado como Global y está manejado de manera diferente de las otras reglas.

245
Seguridad de acceso

Las reglas récord globales tienen un efecto más fuerte que group nivela reglas récord, y
restricción de acceso puesto que aquellos pueden no override. Técnicamente, están
unidos con un Y operador. En los módulos estándares, suelen implementa multi-
acceso de seguridad de la compañía, de modo que cada usuario puede ver sólo su
compañía's dato.
En resumen, regular no las reglas récord globales están unidas junto con un U operador: están
añadidos juntos y un registro es accesible si cualquiera de la regla concede que acceso. Las
reglas récord globales entonces añaden restricciones al acceso dado por el regular reglas récord,
utilizando un Y operador. Las restricciones añadieron por las reglas récord globales no pueden
ser overridden por reglas récord regulares.

Utilizando grupo de seguridad para activar


características
Grupos de seguridad pueden restringir algunas características de modo que son
accesibles únicos de utilizarrs pertenencia a estos grupos. Grupos de seguridad
también pueden heredar otros grupos, así que también conceden sus permisos.
Estos dos características combinaron suele implementar una característica de usabilidad
en Odoo: característica toggling. Grupos de seguridad también pueden ser utilizados
como manera to habilita o inutilizar características para algunos o todo de los usuarios
en un Odoo caso.
Estos espectáculos de receta cómo para añadir opciones a encuadres de configuración
y exhibe los dos métodos para habilitar las características adicionales, haciéndoles
visibles utilizando grupos de seguridad o añadiring les por instalar un módulo adicional.
Para el primer caso, haremos la liberación de libro data una característica adicional
opcional y para el segundo, cuando un ejemplo, proporcionaremos una opción para
instalar el módulo de Notas.

Preparándose
Esta receta utiliza mi_módulo descrito en Capítulo 3, Creando Odoo Módulos.
Necesitaremos grupos de seguridad para trabajar con, así que también necesitas tener
seguido el Añadir acceso de seguridad a receta de modelos.
En esta receta, alguna necesidad de identificadores para referir al addon el nombre técnico
del módulo. Supondremos que es mi_módulo . En caso estás utilizando un nombre
diferente, reemplazar mi_módulo con el nombre técnico real de vuestro addon módulo.

Cómo para hacerlo...


Para añadir las opciones de configuración, seguir el dado da un paso:

1. Para añadir el necesitado dependency y los archivos de dato de XML nuevos, editar el
__openerp__.py Manifiesta así:
# -*- Codificación: utf-8 -*-
{ 'Nombre': 'código de Recetario',

246
Capítulo 10

'Categoría':
'Biblioteca', 'depende':
['base_setup'], 'dato': [
Esecurity/ir.Modelo.Acceso.csv',
esecurity/seguridad_de
biblioteca.xml', 'libro/de
biblioteca_de las vistas.xml',
'vistas/res_config_encuadres.xml
',
],
}

2. Para añadir el grupo de seguridad nuevo utilizado para activación de


característica, editar el libro/ de biblioteca_de la seguridad.xml
Archivo y añadir el registro siguiente a él:
<Récord id="grupo_release_data" modelo="res.Grupos">
<Biblioteca de nombre="de nombre">de campo: campo de
característica de fecha</de liberación> <categoría de
nombre="del campo_id" ref="base.Categoría_de
módulo_escondida" />
</Récord>

3. Para hacer la fecha de liberación del libro visible sólo cuándo esta opción está
habilitada, editamos el campo definition en los modelos/library_book.py
archivo:
# Clase LibraryBook(modelos.Modelo):
# ...
Campos_de liberación = de la
fecha.Fecha( esFecha de
arrendamiento',
Los grupos= soyy_módulo.Liberación_de grupo_data')

4. Editar los modelos/__init__.py Archivo para añadir un archivo de Pitón nuevo


para la configuración que pones modelo:
De . Libro de biblioteca_de la importación
De . Importación res_config_encuadres

5. Para extender el brujo de configuración del núcleo que añade opciones nuevas a
él, añadir los modelos/ res_config_settings.py archivo con este código:
# -*- Codificación: utf-8 -*-
De openerp modelos de importación, fields

Clase ConfigSettings(modelos.TransientModel):
_Hereda = 'base.config.Encuadres'
campos_de fechas_de liberación = de
grupo.Booleano(
"Dirige fechas de liberación del libro",
grupo='base.Usuario_de grupo', el
grupo_implicado= soyy_módulo.Liberación_de
grupo_data')
Campos_de nota = del módulo.Booleano("Insaplicación de Notas
altas")

247
Seguridad de
acceso

6. Para hacer las opciones disponibles en el UI, añadir


vistas/res_config_encuadres.xml Extendiendo la vista de forma:
<?xml Versión="1.0" codificando="utf-
8"?> <odoo>
<Récord id="la vista_general_config_modelo" de
biblioteca="ir.ui.Nombre"> <de nombre de campo="de vista">
Configuración: añade campo de campo</de
opciones> <de Biblioteca base="de modelo">del
nombre.config.Nombre</de campo> <de campo de
encuadres="hereda_id"
ref="Base_setup.Vista_nombre_de campo" /> <de
configuración general="tipo" de arco="xml">
<Nombre de grupo="google" posición="before">
<Liberación de biblioteca="de nombre_de
grupo_Biblioteca" de cuerda="de la fecha"> <!--
Opción de Fechas de la liberación -->
<Etiqueta para="id"
Liberaciones="de cuerda" /> <div>
<Liberación de grupo="de
nombre_de campo_clase" de
fechas="oe_inline"/>
<Etiqueta para="fechas_de
liberación_del grupo" /> </div>
<!-- Opción de notas -->
<Etiqueta para="id" Notas="de
cuerda" /> <div>
<Nota de módulo="de nombre_de campo"
clase="oe_inline"/> <etiqueta para="nota_de
módulo" />
</div>
</Grupo>
</Grupo>
</Campo>
</Récord>
</odoo>
248
Capítulo 10

Después de que upgrading el addon módulo, el dos new opciones de configuración tendrían
que ser disponibles en
Encuadres | Encuadres Generales. La pantalla tendría que parecer esto:

Cómo trabaja...
El módulo de base del núcleo proporciona un res.config.Modelo de encuadres que
proporciona la lógica empresarial detrás optaactivación de ión. La base_setup addon el módulo lo
utiliza para proporcionar la varias configuración básica opciones para hacer disponibles en una
base de datos nueva. También hace disponible el
Encuadres | carta de Encuadres Generales.

La base_setup derivó modelo de configuración es base .config.Encuadres, así que


necesitamos extenderlo para añadir nuestros encuadres de configuración propios.
Si éramos para decidir para crear una forma de encuadres concreta para la aplicación de
Biblioteca, podríamos heredar directamente del res.config.Modelo de encuadres en
cambio, y entonces proporcionar la carta optaión y vista de forma para aquellos encuadres.
Utilizamos dos maneras diferentes para activar las características: uno por habilitador un
grupo de seguridad, haciendo la característica visible al usuario, y el otro por instalar un
módulo addon proporcionando la característica. La lógica para manejar ambos estos
casos está proporcionado por la base res.config. Modelo de encuadres.
249
Seguridad de acceso

El primer paso de receta añade la base_setup addon módulo a las dependencias, desde
entonces proporciona la base.config.Modelo de encuadres queremos uso. También añade
un añadiritional
Archivo de dato del XML necesitaremos añadir las opciones nuevas a la forma de Encuadres
General.

En el segundo paso, creamos una Biblioteca de grupo de seguridad nueva:


característica de fecha de la liberación. La característica para activar tendría
que ser visible sólo para aquel grupo, de modo que seahola dden hasta el grupo
está habilitado.
En nuestro ejemplo, queremos la fecha de liberación del libro para ser disponible sólo
cuándo la opción de configuración correspondiente está habilitada. Para conseguir esto,
utilizamos el atributo de grupos en el campo de modo que está hecho disponible sólo
parathi s grupo de seguridad. Nosotros él en nivel de modelo, de modo que es
automáticamente aplicado a todo el UI vistas donde el campo está utilizado.
Finalmente, extendemos la base.config.Modelo de encuadres para añadir las opciones
nuevas. Cada opción es un campo Booleano , y su nombre tiene que empezar cualquiera por
grupo_ o módulo_ , según qué lo queremos para hacer.

El campo_ de opción del grupo tendría que tener un atributo_de grupo implicado y ser una
cuerda que contiene una coma lista separada de XML IDs para los grupos de seguridad para
activar cuándo está habilitado. El
XML yoDs tiene que ser en la forma completa con identificador de punto de nombre de
módulo nombre.

También podemos proporcionar un atributo de grupo para especificar para qué seguridad
agrupa la característica será habilitada. Sea para todo el empleado basó grupos, si ningún
grupo está definido. Por ello no aplicarán a grupos de seguridad del portal, desde entonces
estos no heredan en el grupo de seguridad de base de empleado, como la otra seguridad
regular grupos.
El mecanismo detrás de la activación es bastante sencillo: añade el grupo de seguridad
en el atributo de grupo al implied_grupo, por ello haciendo la característica
relacionada visible a los usuarios correspondientes.

El campo_ de opción del módulo no requiere cualesquier atributos adicionales. La parte


restante del nombre de campo identifica el módulo para ser instalado cuándo activando la
opción. En nuestro ejemplo, nota_de módulo instalará el módulo de nota.

Amonestación:
Unchecking La caja uninstall el módulo sin advertir, los cuales
pueden causar pérdida de dato (los modelos o los campos
sacados y dato de módulo sacado como consecuencia). Para
evitar unchecking la caja by accidente, el seguro_uninstall
módulo comunitario (de https://github.com/oca/server-tools )
incita para una contraseña antes de que uninstalling el addon
módulo.
El último paso de la receta añade las opciones a la vista de forma de Encuadres General,
justo antes del
Grupo de Integración del Google, habiendo nombre="google".

250
Capítulo 10

Allí ha más...
Encuadre de configuración también puede tener los campos nombraron con el default_
prefijo. Estos cuando habiendo un valor lo pondrá uns un global default. El campo de
encuadres tendría que tener un default_atributo de modelo para identificar el modelo
afectó, y el nombre de campo después del default_ el prefijo identifica el campo del
modelo que habrá puesto el default valor.
Además, campos con ninguno de los tres prefijos mencionó puede ser utilizado para otros
encuadres, pero necesitarás implementar la lógica para poblar sus valores, utilizando
consigue_default_ el nombre prefijó métodos, y para actuar cuándo sus valores están
editados, utilizando nombre_ de conjunto prefijó métodos.
Para quienes gustarían ir más profundos a detalles de encuadres de la configuración, la
documentación mejor disponible es en Odoo es
./openerp/addons/Base/res/res_config.py archivo.
251
11
Internacionalizació
n
En este capítulo, cubriremos los temas siguientes:

f Instalando una lengua y configurar preferencias de


f usuario que Configuran lengua-relacionó encuadres
f Traduciendo textos a través de la interfaz de usuario de
cliente de web
f
Cuerdas de traducción exportadora a un archivo
f
Utilizando gettext herramientas para aliviar
f
traducciones
Archivos de traducción importadora a Odoo

Muchos de estas acciones pueden ser hechos cualquiera de la interfaz de usuario de


cliente de web o de la línea de orden. Siempre que posible, mostraremos cómo para
utilizar cualquier opción.

Instalando un languedad y configurar


preferencias de usuario
Odoo Es localization a punto, significando que apoya varias lenguas y locale encuadres,
como fecha y formatos de número.
Cuando primer instalado, sólo el default la lengua inglesa es disponible. Para tener otras
lenguas y locales disponibles a los usuarios, necesitamos instalarles.

Preparándose
Necesitaremos tener el Modo de Desarrollador activó. Si no es, activa él en el
Odoo Aproximadamente diálogo.

253
Internacionalización

Cómo para hacerlo...


Para instalar un nuevo language en un Odoo caso, seguir estos pasos:

1. Seleccionar las Traducciones de Encuadres de opción | de carta | Cargan una


Traducción. En el diálogo resultante, seleccionar la lengua para instalar de la lista
de lenguas disponibles. Si el sitio web está instalado, tú también be dado la
opción para elegir los sitios web donde la lengua será disponible.

2. Ahora clic en el botón de Carga y la lengua serán instalados.

3. Las lenguas nuevas también pueden ser instaladas de la línea de orden. El


equivalente command para los pasos de preceder es:
$ ./odoo.py -d mydb --Carga-lengua=es_ES

254
Capítulo 11

4. Para poner la lengua utilizada por un usuario, va a Usuarios | de Usuarios | de los


Encuadres y, en el
Tabulador de preferencias de la forma de usuario, puesto el valor de campo de la
Lengua. While Eres en él, puedes utilizar la oportunidad de poner el usuario
Timezone.

Los usuarios pueden también puestos estas configuraciones ellos a través de la opción de
carta de las Preferencias, disponible cuándo ellos clic en el nombre de usuario en el derecho
superior de la ventana de cliente de la web.

Cómo trabaja...
Los usuarios pueden tener su lengua propia y timezone preferencias. El anterior suele
traducir el texto de interfaz del usuario a la lengua escogida y aplicar convenciones locales
para el flotador y campos monetarios. El último suele exhibición el datetime campos en el
correctos timezone.
Antes de una lengua está hecha disponible para los usuarios para seleccionar, tenga que
ser instalado con la Carga una característica de Traducción. La lista de lenguas
instaladas puede ser vista con los Encuadres | Translations | opción de carta de las
Lenguas.
Cada Odoo addon el módulo es responsable para proporcionar sus recursos de traducción
propios que tendría que ser colocado dentro de un i18n subdirectorio. El dato de cada
lengua tendría que ser en un .po Archivo. Siguiendo nuestro ejemplo, para el
españollangua ge, el dato de traducción está cargado del es_es.po archivo de dato.
255
Internacionalización

Odoo También apoya la idea de lengua de base. Por ejemplo, si tenemos un es.po
archivo para español y un es_mx.po archivo para español mexicano, entonces es.po está
detectado como la lengua de base para es_mx.po. Cuándo la lengua española mexicana
está instalada, ambos archivos de dato están cargados; primero el para la lengua de base y
entonces la lengua concreta está instalada. Así, el archivo de traducción de lengua concreto
sólo needs para contener las cuerdas que es concreto a la variante de lengua, español
mexicano en nuestro ejemplo.
El i18n el subdirectorio es también esperado para tener <un nombre_de
módulo>.Archivo de tarro, proporcionando una plantilla para traducciones y conteniendo
todo el translatable cuerdas. Las cuerdas de traducción de la Exportación a una receta de
archivo explica cómo para exportar el translatable cuerdas para generar este archivo.

Cuándo una lengua adicional está instalada, los recursos correspondientes están
cargados de todo instalados addon módulos y almacenados en el T ranslated modelo de
Plazos. Su dato puede ser visto (y editado) con los Plazos | de Aplicación | de
Traducciones de Encuadres | Tradujeron opción de carta de los Plazos.
Archivos de traducción para las lenguas instaladas son también cargados cuándo un
nuevos addon el módulo es instalado o un existing addon el módulo es upgraded.

Allí ha más...
Archivos de traducción pueden ser reloaded sin upgrading el addon módulos por repetir la
Carga una acción de Traducción. Esto puede ser utilizado en caso has actualizado archivos
de traducción y no quiere pasar por elt rublo de upgrading los módulos (y todas sus
dependencias).
Si el Overwrite Existiendo Plazos checkbox queda vacío, sólo la cuerda traducida nueva está
cargada. Así, el cambió la cuerda traducida no será cargada. Control la caja si quieres el ya
existiendo traducciones a también ser cargados y overwrite las traducciones actualmente
cargadas.

El anterior checkbox existe porque podemos hacer nuestras traducciones concretas que
editan Encuadres
| Plazos | de Aplicación de las traducciones | Tradujeron Plazos, o utilizando el Técnicos
Translation opción de atajo en el Depurar carta. Las traducciones añadidas o modificó de este
modo no será overwritten a no ser que la lengua es reloaded con el Overwrite Existiendo Plazos
checkbox habilitó.

Pueda ser útil de saber que el addon los módulos también pueden tener un
i18n_subdirectorio extra con traducciones extras. La secuencia de cargar para los
archivos de traducción es: el .po Archivos en el i18n subdirectorio, primero para la
lengua de base y entonces para la lengua; entonces el .po Archivos en el
i18n_subdirectorio extra, primero para la lengua de base y entonces para la lengua. La
última traducción de cuerda cargada es el aquello prevalece.

Ve también
La lista de códigos de lengua puede ser vista en el código de fuente; en el
odoo/openerp/herramientas/ misc.py archivo, buscar la TODA_variable de LENGUAS.
El GitHub el enlace para el archivo es
https://github.com/odoo/odoo/blob/9.0/openerp/tools/misc.py.

256
Capítulo 11

Configura lengua-relacionó encuadres


Lenguas y su variationes (como es_MX para español mexicano) también proporcionar
locale encuadres como fecha y formatos de número.
Vienen con apropiados defaults, así que mientras el usuario está utilizando la lengua
correcta, el locale los encuadres tendrían que ser el apropiados unos.
Pero todavía podrías querer modificar los encuadres de una lengua. Por ejemplo, podrías
preferir tener la interfaz de usuario en el default inglés, pero quiere cambiar el americano
default fecha y formatos de número a vuestras necesidades.

Preparándose
Necesitaremos tener el Developer el modo activó. Si no es, activa él en el Odoo
Aproximadamente diálogo.

Cómo para hacerlo...


Para modificar una lengua locale encuadres, seguir estos pasos:

1. Para comprobar las lenguas instaladas y sus configuraciones, seleccionar los


Encuadres |
Traducciones | Languages opción de carta. Clicking Encima uno de las lenguas
instaladas abrirá una forma con los encuadres correspondientes:

2. Editar los encuadres de lengua. Para cambiar la fecha al formato de ISO, Formato de
Fecha del cambio a %Y-%m-%d , y para cambiar el número format para utilizar una coma
como decimal separator, modificar el Decimal Separator y Miles Separator campos
consiguientemente.
257
Internacionalización

Cómo trabaja...
Cuándo firmando en y creando un nuevo Odoo sesión de usuario, la lengua de usuario
está comprobada ent él preferencias de usuario y puestos en el lang llave de contexto.
Esto es entonces utilizado a formato las producciones apropiadamente: los textos de
fuente están traducidos a la lengua de usuario, y las fechas y los números son formatted
según la lengua actual locale encuadres.

Allí ha más...
Procesos de lado del servidor son capaces de modificar el contexto en qué acciones está
corrido. Por ejemplo, para conseguir un conjunto récord donde las fechas son formatted según
el formato inglés independiente de la preferencia de lengua del usuario actual, podrías hacer
el siguiente:
en_Registros = self.Con_contexto(lang='en_EN').Búsqueda([])

Para más detalles, refiere a Capítulo 6, Desarrollo de Lado de Servidor Adelantado receta de
Técnicas
Llamando un método con un contexto modificado.

Traduce textos a través del usuario de


cliente de la web enterface
La manera más sencilla de traducir es para utilizar la característica de traducción
proporcionada por el cliente de web. Estas cuerdas de traducción están almacenadas en
la base de datos y más tarde puede ser exportado a un .po Archivo, tampoco para ser
incluido en un addon módulo o justo a más tarde ser importado atrás manualmente.
Campos de texto pueden tener translatable contenido, significando que su valor dependerá de la
lengua del usuario actual. También veremos cómo para poner la lengua-valores dependientes en
estos campos.

Preparándose
Necesitamos tener el Developor el modo activó. Si no es, activa él en el Odoo Aproximadamente
diálogo.

Cómo para hacerlo...


Demostraremos cómo para utilizar traducir plazos a través del cliente de web que utiliza la
característica de Grupos del Usuario como un ejemplo:
1. Navigate A la pantalla para traducir. Seleccionar el Se ttings carta superior y
entonces los usuarios abiertos | Agrupa para abrir la vista correspondiente.
258
Capítulo 11

2. En la barra de carta superior, clic en el Depurar icono de carta y seleccionar


la opción de Traducción Técnica:

3. Una lista de los plazos de traducción disponibles para aquella vista serán
mostrados. Edita Valor de Traducción en una línea para cambiar (o añadir) su texto
de traducción. Si buscando una cuerda de fuente particular, uso los filtros de lista
para angostar abajo el mostró textos:

El nombre de Grupo es un translacampo de mesa. Dejado es traducir el valor de un


registro a las varias lenguas instaladas:

259
Internacionalización

4. Navigate Otra vez a la opción de carta de Grupos de Usuario, abre uno de los registros
de grupo en la vista de forma, y el clic encima Edita:

5. Notatha t el campo de Nombre tiene un icono especial en el derecho lejano. Esto


indica que es un translatable campo. Clicking En el icono abre un Traducir lista con
las lenguas instaladas diferentes, dejándonos para poner la traducción para cada de
aquellas lenguas.

Cómo trabaja...
Tradujo los plazos están almacenados en la mesa de base de datos para el modelo
ir.Traducción. La opción de Traducción Técnica en el Depurar la carta proporciona un
acceso rápido a aquellos plazos, en contexto con la vista actualmente seleccionada.
De modo parecido, el modelo fields con translatable el contenido presenta un icono para
acceder la lista de las lenguas instaladas y para poner el valor apropiado para cada
lengua.
Alternativamente, los plazos de traducción pueden ser accedidos de los Encuadres carta
superior, utilizando el
Traducciones | AppliPlazos de catión | Tradujeron opción de carta de los Plazos. Aquí
podemos ver todos los plazos disponibles para nuestro caso, pero tendría que necesitar
utilizar filtros de dato para localizar los plazos podríamos ser interesados en.

Allí ha más...
Junto al Traducido Denomina opción de carta, también encontramos el Sincronizar opción
de Plazos. Seleccionándolo mostrará una ventana de diálogo para proporcionar la lengua
deseada, y entonces lanzará el proceso para extraer translatable cuerdas del instalados
addon módulos y añadir cualquier nuevo unos al Tradujo Plazos table. Es equivalente a
actuar la Traducción de Exportación seguida por los pasos de Traducción de la Importación
describieron más tempranos.
Esto puede ser útil después de cambiar algunos modelos o vistas, para tener las cuerdas
nuevas añadieron de modo que les podemos traducir.
También pueda seruso d para poblar las cuerdas del en_EE.UU. default lengua.
Podemos entonces uso de marca de los plazos de traducción para reemplazar los textos
ingleses originales con nuevos unos, mejores para el vocabulario empresarial concreto del
usuario de fin.
260
Capítulo 11

Exportador translation cuerdas a un archivo


Cuerdas de traducción pueden ser exportadas con o sin el tradujo textos para una
lengua seleccionada. Esto puede ser tampoco para incluir en un módulo i18n dato, o
a más tarde actuar las traducciones con un editor de texto o quizás con uns pecialized
herramienta.
Demostraremos cómo para hacerlo utilizando el módulo de correo estándar, así que
siente libre de reemplazar correo con vuestro módulo propio.

Preparándose
Necesitamos tener el Modo de Desarrollador activó. Si no es, activa él en el Odoo
Aproximadamente diálogo.

Cómo para hacerlo...


Para exportar los plazos de traducción para el correo addon módulo, seguir estos pasos:
1. En la interfaz de usuario de cliente de web, de los Encuadres la carta superior
selecciona las Traducciones |
Traducción/de Exportación | de Exportación de importación opción de carta.
2. En las Traducciones de Exportación dialog, escoger la traducción de lengua para
exportar, el formato de archivo, y los módulos para exportar. Para exportar un archivo
de plantilla de la traducción, selecciona
Lengua nueva (plantilla de traducción Vacía) de la lista de selección de la
Lengua. Está recomendado para utilizar el .po Formato unnd para exportar sólo
uno addon módulo a la vez—el Hablar (correo nombre técnico) módulo en
nuestro ejemplo:
261
Internacionalización

3. Una vez el proceso de exportación es completo, una ventana nueva será mostrada,
con un enlace para descargar tarchive y algunos consejo adicional:

4. Para exportar del Odoo interfaz de línea de la orden un archivo de plantilla de la


traducción para el correo addon módulo:
$ ./odoo.py -d mydb --i18n-exportar=mail.po --correo=de
módulos $ mv mail.po ./addons/Correo/i18n/correo.Tarro

5. Para exportar del Odoo interfaz de línea de la orden el archivo de plantilla de la


traducción para una lengua, es_ES para español, por ejemplo:
$ ./odoo.py -d mydb --i18n-exportar=es_es.po --correo=de
módulos --lengua=es_ES
$ mv es_es.po ./addons/Correo/i18n

Cómo trabaja...
The Característica de Traducción de la exportación dos cosas: primero extrae el
translatable cuerdas de los módulos de objetivo, añadiendo el nuevos unos en el
ir.Modelo de traducción, y entonces crea un archivo con los plazos de traducción. Esto
puede ser hecho ambos del cliente de web y la interfaz de línea de la orden.
Cuándo exportando del cliente de web, podemos escoger a cualquier exportación una
plantilla de traducción vacía – un archivo con las cuerdas para traducir junto con
traducciones vacías, o exportar una lengua, resultando en un archivo con el strings para
traducir junto con la traducción ya hecha para la lengua seleccionada.
Los formatos de archivo disponibles es CSV, PO, y TGZ. El TGZ formato de archivo exporta un
archivo comprimido que contiene un nombre de estructura <del directorio>/i18n/
con el PO o archivo de TARRO.

262
Capítulo 11

El CSV el formato puede ser útil de actuar las traducciones que utilizan un spreadsheet, pero el
formato para utilizar en el addon los módulos es el PO archivos. Estos están esperados para ser
colocados dentro del i18n subdirectorio, y si así que es automáticamente cargado una vez la
lengua correspondiente está instalada.
Cuándo exportando estos PO archivos, tendríamos que exportar sólo un módulo a la vez. El
PO el archivo es también un formato popular apoyado por herramientas de traducción, como
Poedit.
Las traducciones también pueden ser exportadas directamente delc ommand línea,
utilizando el --i18n-opción de exportación. Los espectáculos de receta cómo para extraer
ambos los archivos de plantilla y los archivos de lengua traducidos.
En Paso 4 de la sección anterior, exportamos un archivo de plantilla. El --i18n-opción de
exportación espera el camino y el nombre de archivo para exportar. Mente que la extensión de
archivo está requerida para ser cualquier CSV, PO, o TGZ. Esta opción requiere el -d opción,
especificando la base de datos para utilizar.
El --opción de módulos es también necesitada para indicar el addon módulos para exportar.
Nota que el --parón-after-init la opción no es necesitada, desde la orden de
exportación automáticamente regresa a la línea de orden cuándo acabada.
Esto exporta un archivo de plantilla, aquello en un módulo está esperado para tener la
extensión de TARRO. Cuándo trabajando en un módulo, después de la operación de
exportación normalmente queremos mover el exportados PO archivo al módulo i18n
directorio con un <módulo>.Nombre de tarro.

En Paso 5, el --opción de lengua era también utilizó. Con él, en vez de un archivo de
traducción vacío, el tradujo los plazos para la lengua seleccionada eran también exported.
Uno utiliza caso para este es para actuar algunas traducciones a través de la interfaz de
usuario de cliente de web que utiliza la característica de Traducción Técnica, y entonces
exportando e incluyéndoles en el módulo.

Allí ha más...
Cuerdas de texto en vista y definiciones de modelo are automáticamente extraídos para
traducción. Para modelos, el _atributo de descripción, los nombres de campo (el
atributo de cuerda), texto de ayuda, y opciones de campo de la selección están extraídas,
así como los textos de usuario para constreñimientos de modelo (_
Constreñimientos y _sql_constr aints).

Cuerdas de texto para traducir Pitón de interior o código de Javascript no pueden ser
automáticamente detectado, así que el código tendría que identificar aquellas cuerdas,
envolviéndoles interior el underscore función.
En un archivo de Pitón del módulo, tendríamos que hacer seguro está importado con el
siguiente:

De openerp importación _

Entonces pueda ser utilizado wherever un translatable el texto está utilizado con algo así:
_('Hola Mundo')

Para cuerdas que uso información de contexto adicional, tendríamos que utilizar
interpolación de cuerda de la Pitón, así:
_('Infiernoo %s') % 'Mundo'

263
Internacionalización

Nota que la interpolación tendría que ir fuera de la función de traducción. Por ejemplo,
_("Hola %s" % 'Mundo') es mal. Interpolaciones de cuerda también tendrían que ser
preferidas a concatenación de cuerda, de modo que cada texto de interfaz es justo una
cuerda de traducción.

Amonestación con los campos de Selección! Si pasas una lista explícita de


valores a la definición de campo, entonces el mostró las cuerdas son
automáticamente flagged para traducción. Por otro lado, si pasas un
conocidohod regresando la lista de valores, entonces las cuerdas de
exhibición tienen que ser explícitamente marcadas para traducción.

Con respecto al trabajo de traducción manual, cualquier editor de archivo del texto puede
hacer, pero utilizando un archivo que apoya el PO sintaxis de archivo hace el trabajo más
fácil por reducir el riesgo de formatting errores. Tales editores incluyen:
f poedit (https://poedit.net/)
femacs (po-Modo)
(https://www.gnu.org/software/gettext/manual/html_nodo/PO-
Modo.html)
f Lokalize (http://i18n.kde.org/tools)
f Gtranslator (https://wiki.gnome.org/apps/gtranslator)

Uso gettext herramientas para aliviar


traducciones
El PO formato de archivo es parte del gettext internacionalización y localization el sistema
generalmente utilizado en sistemas estilo Unix. Este sistema incluye herramientas a ease el
trabajo de traducción.
Esta receta demuestra cómo para utilizar estas herramientas para ayudar traducen
nuestro addon módulos. Lo queremos utilizar encima un módulo hecho de encargo, así
que mi_módulo creado en Capítulo 3, Creando Odoo los módulos es un candidato bueno .
Pero sentir libre de reemplazarlo with algunos otro módulo hecho de encargo has a mano,
reemplazando la receta es mis_referencias de módulo como apropiado.

Cómo para hacerlo...


Para dirigir la traducción de la línea de orden, suponiendo que vuestro Odoo la instalación
es ~en /odoo-trabajo/odoo, seguir estos pasos:
1. Crear un compendium de plazos de traducción para la lengua de objetivo, por ejemplo,
Español. Si nombramos nuestro compendium archivo odoo_es.po
tendríamos que escribir el código siguiente:
$ cd ~/odoo-Trabajar/odoo # Utilizar el camino a vuestro Odoo
instalación
$ Encontrar ./ -Nombre es_ES.po | xargs msgcat --Uso-primer |
msgattrib \ --traducido --no-borroso -o ./odoo_es.po

264
Capítulo 11

2. Exportación del Odoo interfaz de línea de la orden el archivo de plantilla de la


traducción para el addon módulo y sitio él en el módulo está esperado ubicación:
$ ./odoo.py -d mydb --i18n-exportar=my_module.po --módulos=mi_módulo $
mv my_module.po ./addons/Mi_módulo/i18n/mi_módulo.Tarro

3. Si ningún archivo de traducción es disponible todavía para la lengua de objetivo,


crear el PO archivo de traducción, reusing los plazos ya encontrados translated en el
compendium:
$ msgmerge --compendium ./odoo_es.po \
-o ./addons/Mi_módulo/i18n/es_es.po \ /dev/null
./addons/Mi_módulo/i18n/mi_módulo.Tarro

4. Si un archivo de traducción existe, añadir las traducciones que puede ser encontrado en
el compendium: $ mv ./addons/Mi_módulo/i18n/es_es.po
/tmp/my_module_es_old.po
$ msgmerge --compendium ./odoo_es.po \ -
o./addons/Mi_módulo/i18n/es_es.po \
/tmp/my_module_es_old.po
./addons/Mi_módulo/i18n/mi_módulo.Tarro $ rm
/tmp/my_module_es_old.po

5. Para tener un peek en el untranslated plazos en un PO archivo:


$ msgattrib --untranslated ./addons/Mi_módulo/i18n/es_es.po

6. Uso vuestro editor favorito para completar la traducción.

Cómo trabaja...
Paso 1 de la sección de preceder llamadas odoo.py con el --i18n-opción de exportación.
Necesitas especificar un database en la línea de orden, incluso si uno está especificado en el
archivo de configuración y el --opción de módulos, con una coma lista separada de módulos
para exportar la traducción para.
Paso 2 órdenes de usos del gettext toolbox para crear una traducción compendium para la
lengua escogida, español en nuestro caso. Trabaja por encontrar todo el es_es.po archivos
en el Odoo base de código, y pasándoles al msgcat orden. Utilizamos el --uso-primera
bandera para evitar que choca traducciones ( hay unos cuantos en el Odoo base de código). El
resultado está pasado al msgattrib filtro. Utilizamos el --opción traducida para filtrar fuera
del untranslated entradas y el --opción no borrosa para sacar las traducciones borrosas.
Entonces salvamos el resultado en
odoo_es.po.

En el gettext mundo, borroso translations es aquellos crearon


automáticamente por el msgmerge orden (u otras herramientas) por
utilizar un proximity partido en la cuerda de fuente. Queremos evitar
estos en el compendium.

265
Internacionalización

Paso 3 crea un archivo de traducción que utiliza el translated valores para los textos ya
encontrados en el compendium. El msgmerge la orden está utilizada con el --compendium
opción para encontrar en el compendium archiva el msgid las líneas que emparejan aquellos en
el archivo de plantilla de la traducción generado en
Paso 1. El resultado está salvado ent él es_es.po archivo.

Si tienes un preexistente .po Archivo para vuestro addon con traducciones te gustaría
preservar, entonces lo tendrías que rebautizar y reemplazar el /dev/null argumento con
este archivo. El rebautizar está requerido para evitar utilizando el mismo archivo ambos para
enpuestos y producción.

Allí ha más...
Esta receta sólo skims las herramientas ricas del GNU gettext toolbox. La cobertura llena es bien
allende el alcance de este libro. Si estás interesado, el GNU gettext la documentación contiene
una riqueza de información preciosa sobre PO manipulación de archivo, y es disponible en
http://www.gnu.
org/Software/gettext/manual/gettext.html.

Importación translation archivos


La práctica habitual para cargar las traducciones es por colocar el PO archivos dentro del
módulo i18n subdirectorio. Siempre que el addon el módulo es instalado o upgraded, los
archivos de traducción son cargados y el nuevos tradujo las cuerdas están añadidas.
Peroth antes de puede ser casos donde queremos directamente importar un archivo de
traducción. En esta receta, veremos cómo para cargar un archivo de traducción, cualquiera del
cliente de web o de la línea de orden.

Preparándose
Necesitamos tener el Modo de Desarrollador activó. Si esningún t, activa él en el Odoo
Aproximadamente diálogo.
Somos también esperados para tener un archivo de traducción para ser importado;
myfile.po, por ejemplo.

Cómo para hacerlo...


Para importar los plazos de traducción, seguir estos pasos:

1. En la interfaz de usuario de cliente de web, de los Encuadres top la carta selecciona las
Traducciones |
Traducción/de Importación | de Exportación de importación opción de carta.
2. En el diálogo de Traducciones de la Importación, llena fuera del nombre de lengua y el
código de lengua, y seleccionar el archivo para importar. Finalmente, clic en el botón de
Importación para actuar el action.
266
Capítulo 11

3. Para importar del Odoo interfaz de línea de la orden un archivo de traducción, lo


tenemos que colocar interior el servidor addons camino y entonces actuar la
importación:
$ mv myfile.po ./addons/
$ ./odoo.py -d mydb --i18n-importar="myfile.po" --lang=es_ES

Cómo trabaja...
Traducción de importación toma un PO o CSV archivo y carga las cuerdas de
traducción al ir.Mesa de traducción.
La característica de cliente de la web pide el nombre de lengua, pero esto no es utilizado en
el proceso de importación. También tiene un overwrite opción. Si seleccionado, fuerza todas
las cuerdas de traducciones para ser importados, incluso los que ya existen, overwriting les
en el proceso.
En la línea de orden, la importación puede ser hecha utilizando el --i18n-opción de
importación. Tenga que ser proporcionado con el camino al archivo, pariente a un addon
directorio de camino. -d Y --lengua.
(O -l ) es obligatorio. Overwriting También puede ser conseguido por añadir el --i18n-
overwrite opción a la orden. Nota que no utilizamos el --parón-después de que-
init opción. No es necesitado, desde la acción de importación para el servidor cuándo
acaba.
267
12
Automatización
y
Workflows
En este capítulo, mostraremos cubrir los temas siguientes:

f Utilizando Kanban etapas y


f características Creating acciones
f de servidor
f Añadiendo messaging y siguiendo las
f características que Utilizan acciones de
f servidor de código de Pitón
f Utilizando automatizó las acciones
puntualmente condiciona Utilizar automatizó
acciones encima condiciones de
acontecimiento
Inspeccionando construido-en workflows

Introducción
Las aplicaciones empresariales sonex pected no sólo para almacenar registros, pero también
para dirigir empresarial workflows. Odoo Incluye un workflow motor, pero es cada vez más
utilizado menos en versiones más tardías del producto. En cambio, reglas de automatización y
Kanban los tableros están utilizados siempre que posibles.
El automation las reglas son más pertinentes para customization que para nuevos addon
desarrollo de módulos, pero los desarrolladores todavía tendrían que ser familiares con ellos.
Haciendo así que puede evitar encima-engineered reglas empresariales que podría ser
implementado a través de funcional customizations. Algunos de estas técnicas también
pueden ser utilizadas por usuarios de poder o asesores funcionales para añadir algunos
automatización de proceso más sencillo sin la necesidad de crear hecha de encargo addons.

269
Automatización y Workflows

Utilizando Kanban etapas y características


El Kanban el tablero es un método sencillo para dirigir workflows. Está organizado en columnas,
cada correspondientes a etapas, y el progreso de elementos del trabajo de izquierdo a correcto
hasta que están acabados.
Hay unas cuantas características utilizó a través de varios Kanban tableros,
proporcionando un patrón común tel sombrero también puede ser utilizado en nuestros
módulos hecho propios. Dejado visita aquellas características.

Preparándose
Para seguir esta receta, necesitarás tener la aplicación de Administración del Proyecto ya
instalada.

Cómo para hacerlo...


Para empezar con unas Tareas de Proyecto Kanban tablero:

1. Select El Proyecto opción de carta superior y entonces Crear un Proyecto nuevo.


2. Dar un nombre al Proyecto nuevo y pegar el Salvar botón. Luego, prensa en las
Tareas botón listo en el derecho superior de la forma. Esto abrirá el Kanban
vista para las Tareas de Proyecto.
3. Clic en el Añadir Columna Nueva barra vertical en el correcto, tipo Ahora en la
caja de diálogo pequeña, y el clic encima Añade. Repite a también añadir el más
Tardío y Hecho escenifica.
4. Cercar el puntero de ratón sobre la etapa Hecha y un cog icono de rueda será
mostrado. Clic encima lo y elegir Editar de la carta de opción.
5. En el Editar ventana de Columnas, control el Plegado en caja de Tubería de las
Tareas y salvar, cuando mostrado en el siguiente screenshot:
270
Capítulo 12

Cómo trabaja...
Kanban Es uno de los tipos de vista disponibles, y es capaz de organizar los elementos
agruparon en columnas. Si utilizamos etapas para agrupar los elementos de trabajo,
conseguimos un Kanban tablero. La lista de etapa puede ser configurada para caber las
necesidades concretas del usuario.
Las etapas tendrían que tener un atributo plegado, significando que el corresponding columna
en el Kanban la vista tendría que ser mostrada plegó. El trabajo en elementos de progreso
está esperado para ser en una etapa desdoblada, y rescindió elementos, normalmente
Hechos y Cancelados , tendría que ser en Plegó etapas.
Cada elemento de trabajo tiene una referencia para la etapa es en. Yot también puede
tener un Kanban Estado, representado por una señal de tráfico-como ligero, y una
Prioridad, representado por una estrella. El Kanban las tarjetas también pueden tener
un atributo de color, utilizado para su color de fondo.
271
Automatización y Workflows

Mientras la etapa representa el estado actual en el proceso para el elemento de trabajo,


Kanban el estado proporciona información sobre su readiness para adelantar a la etapa
próxima. Es un campo de Selección, normalmente nombrado kanban_estado, en la
forma, y Kanban las vistas está utilizada con el kanban_ selección_estatal widget y
espera tres opciones posibles:
f Un valor neutro gris, el default (el valor de base de datos normal)
fUn valor "Bloqueado" rojo (elvalorde base de datos bloqueado), significando
que hay algunarazón para retener el elemento de trabajo en elcur etapa de
alquiler
fUn verde "A punto para el valor de etapa" próximo (elvalorde base de datos
hecho), significando que elelemento de trabajo está a punto para ser estirado para
la etapa próxima
La Prioridad es también un campo de Selección, y está mostrado con la prioridad especial
widget en la formaun d Kanban vistas. Las opciones de selección están esperadas para ser
cualquiera una cuerda con un número, empezando en 0, para valor normal (no protagonizado),
y otros valores para protagonizó opciones.

Allí ha más...
Las etapas están añadidas a modelos a través de un Mucho2un campo referencing un
modelo de etapa que define las etapas posibles. Encima vistas de forma, pueden ser
representados con la ayuda del statusbar tubería widget. Para más detalles en vistas,
widgets, y diseñando Kanban vistas, puedes referir a Capítulo 8, Backend Vistas.
El complementario Kanban el estado se mantiene con un campo de Selección y su definición
típica es:

kanban_Campos = estatales.Selección(
[('Normal', 'Normal'),('bloqueado', 'Bloqueado'),('hecho',
esady para etapa próxima')],
'Kanban Estatal',
default='normal')

Encima vistas de forma, tenga que use el concreto kanban_selección_estatal widget:


<Nombre de campo="kanban_estado" widget="kanban_selección_estatal" />

Con respecto al campo de Prioridad, es también un campo de Selección, y el número de


opciones normalmente gamas entre 2 y 4 elementos de selección:
Campos = de prioridad.Selección(
[('0', 'Normal'), ('1', 'Bajo'), ('2',
'Alto'), ('3', 'Muy Alto')],
'Prioridad', default='0')

En vistas de forma, pueda hacer uso de la prioridad concreta widget:


<Prioridad de nombre="del campo" widget="prioridad"/>
272
Capítulo 12

Creating Acciones de servidor


Acciones de servidor underpin el Odoo herramientas de automatización. Nos dejamos
para describir las acciones para actuar. Estas acciones son entonces disponibles de
apellidarse por gatillos de acontecimiento, o para ser provocados automáticamente
cuándo condiciones de tiempo seguro están conocidas.
El caso más sencillo es para dejar el usuario de fin actúa alguna acción en un documento por
seleccionar él de la Más carta de botón. Crearemos tal una acción para tareas de proyecto, para
Poner tan Prioridad por protagonizar la tarea actualmente seleccionada y poniendo una fecha
límite eni t a tres días de ahora.

Preparándose
Necesitaremos un Odoo caso con la aplicación de Proyecto instalada. También
necesitaremos el Modo de Desarrollador activó. Si no es, activa él en el Odoo
Aproximadamente diálogo.

Cómo para hacerlo...


Para crear una acción de servidor y uso él de la Más carta, seguir estos pasos:

1. En los Encuadres carta superior, seleccionar las Acciones | de Servidor | de


Acciones Técnicas elemento de carta, y clic en el Crear botón en la parte superior
de la lista récord.
273
Automatización y
Workflows

2. Llena fuera de la forma de acción del servidor con estos valores:


‰‰ Nombre de acción: Pone tan
Modelo ‰‰ de Base de la
Prioridad: Tarea
‰‰ Acción para Hacer: Escribe En un Registro
‰‰ Política de actualización: Actualización el Registro Actual
3. En la acción de servidor, bajo el campo de Mapeo del Valor, añade the
siguiendo líneas:
‰‰ Cuando el primer valor, introduciremos los parámetros siguientes:
‰‰ Campo: Fecha límite
‰‰ Tipo de evaluación: expresión de Pitón
‰‰ Valor: datetime.Fecha.Hoy() + datetime.
timedelta(Días=3)
‰‰ Cuando el segundo valor, introduciremos los parámetros siguientes:
‰‰ Campo: Prioridad
‰‰ Tipo de evaluación:
Valor
‰‰

Valor: 1
El siguiente screenshot muestra el introdujo valores:
274
Capítulo 12

4. Salvar la acción de servidor y clic en el Añadir en el soymena' Culataencima en el


derecho superior, para hacerlo disponible en el más botón de la tarea de Proyecto.
5. Para probarlo fuera, va al Proyecto carta superior, seleccionar el elemento | de
carta de Tareas de Búsqueda, y abrir una tarea aleatoria. Por clicking en el Más
botón, tendríamos que ver el Pone tan opción de Prioridad. Seleccionándolo
protagonizará la tarea y cambiar la fecha de fecha límite a tres días de ahora.

Cómo trabaja...
Trabajo de acciones del servidor en un Modelo, así que uno de las primeras cosas para
hacer es para elegir el Modelo de Base queremos trabajo con. En nuestro ejemplo,
utilizamos Tareas de Proyecto.
Luego, tendríamos que seleccionar el tipo de acción para actuar. Hay unas cuantas opciones
disponibles:

f Envía el email deja escoger una plantilla de email, y lo utilizará para enviar fuera
de un email cuándo la acción está provocada.
f Gatillo un Workflow Signal hace justo aquello. En Odoo Workflows, las
señales pueden ser provocadas y utilizadas para despedir workflow
f transiciones.
Corrido una Acción de Cliente provoca un cliente o acción de ventana, justo
f gustar cuándo un elemento de carta es clicked.
Crea o Copiar un Registro nuevo te dejas para crear un registro nuevo, en el actual
f o en otro Modelo.

Escribe en un Registro te dejas para poner valores en el actuales o en otro registro.
Ejecuta Código de Pitón te dejas para escribir código arbitrario para ejecutar,
f
cuándo ninguno de las otras opciones es bastante flexible para qué necesitamos.

Para nuestro ejemplo, utilizamos Escribir en un Récord de poner algunos valores en el registro
actual. Ponemos Prioridad a 1 , para protagonizar la tarea, y poner un valor en el campo de
Fecha límite. Esto uno es más interesante, desde el valor a uso está evaluado de una Pitón
expression. Nuestras marcas de ejemplo
Uso del datetime módulo de Pitón (ve https://docs.python.org/2/library/
datetime.html) Para computar tdate tres días de hoy.

Expresión de Pitón arbitraria puede ser utilizada allí, así como en varios de la otra acción
escribe disponible. Para razones de seguridad, el código está comprobado por el
seguro_eval función, implementado en
odoo/openerp/herramientas/safe_eval.py. TSuyo significa que algunas operaciones
de Pitón no pueden ser dejadas, pero esto raramente prueba para ser un problema.
275
Automatización y Workflows

Allí ha más...
El código de Pitón está evaluado en un contexto restringido, donde los objetos siguientes son
available para utilizar:
fenv: Esto es una referencia para el objeto de Entorno, justo
comoself.envEnmétodo de clase.
fModelo:Esto es una referencia a la clase de modelo los actos de acción del
servidor a. En nuestroejemplo, es equivalente a self.env['Proyecto.Tarea] .
f workfAbajo: Esto es una referencia al Odoo workflow objeto de servidor del motor.
fAviso: Esto es una referencia a openerp.Excepciones.Aviso,
dejandopara validaciones que bloque unintended acciones. Pueda ser
utilizado cuando: levanta
Aviso( soyessage!').
fObjetoo obj: This proporciona referencias al registro actual, dejándote para
accedersus valores de campo y métodos.
fRegistro: Esto es una función a mensajes de registro
enir.loggingModelo, dejando paralado de base de datos logging
en acciones.
f datetime, dateutil, y tiempo : Estos provide acceso a las bibliotecas de Pitón.

Añadiendo messaging y siguiendo


características
Odoo Las características sociales están utilizadas en muchos de las aplicaciones estándares.
Proporcionan una manera fácil para el usuario para ser actualizado y para colaborar alrededor
de documentos empresariales. Es, por tanto, importante para el hecho de encargo addon
módulos a también apoyarles.
Estas características están proporcionadas por el Hablar aplicación (el correo nombre
técnico) y su la mayoría de aspecto visible es la pared de mensaje en el fondo de la forma
para un documento empresarial, junto con el follower caja en su lado derecho.
276
Capítulo 12

Preparándose
Utilizaremos mi_módulo introducido en Capítulo 3, Creando Odoo Módulos, definiendo el
Modelo de Libro de la biblioteca. Puedes conseguir aquel código o deprisa crear un
addon alrededor de este modelo:
# -*- Codificación: utf-8 -*-
De openerp modelos de importación,
clase de campos
LibraryBook(modelos.Modelo):
_Nombre = 'biblioteca.Libro'
Campos = de nombre.Char('Título',
requerido=Cierto) campos_de liberación = de
la fecha.Fecha( esFecha de arrendamiento')
Autor_ids = fields.many2muchos( ess.Socio', cuerda='Autores')

También necesitaremos un archivo de XML con la vista de forma correspondiente:

<Forma>
<Grupo>
<Nombre de nombre="del campo"/>
<Autor de nombre="del campo_ids"
widget="muchos2mucho_grupo"/> </de etiquetas>
<Grupo>
<Liberación de fecha="de
nombre_de campo"/> </grupo>
</Forma>
277
Automatización y Workflows

Cómo para hacerlo...


Para habilitar la red social y siguiendo características en el modelo de Libro de la
Biblioteca, seguir estos pasos:
1. Añadir la dependencia de correo al addon módulo __openerp__.py Manifiesta
archivo:
'Depende': [ soyaqueja'],

2. Editar la biblioteca.Modelo de libro para añadir el código destacó luego:


Clase LibraryBook(modelos.Modelo):
_nombre = 'biblioteca.Libro'
_Descripción = 'Libro de
Biblioteca' _heredar = [
soyaqueja.Hilo']
Campos = de nombre.Char('Título',
requerido=Cierto, visibilidad_de
pista=Cierta) campos_de liberación = de la
fecha.Fecha( esFecha de arrendamiento',
Visibilidad_de pista=Cierta)
Autor_ids = campos.Muchos2muchos( ess.Socio',
cuerda='Autores')

3. Añade a la biblioteca.Modelo de libro el método siguiente:


def _Subtipo_de pista(self,
init_valores): si 'liberación_de
fecha' en init_valores:
El regreso
soyail.mt_comenta' el regreso
Falso

4. Añadir la pared de mensaje widgets a la vista de forma, justo antes de la </etiqueta>


de encierro de la forma:
<div Clase="oe_chatter">
<Seguidor de mensaje="de nombre_de campo_ids"
widget="seguidores_de correo"
agrupa="base.
Usuario_de grupo" />
<Mensaje de nombre="del campo_ids"
widget="hilo_de correo"
/>
</div>

Después de instalar estos cambios, tendríamos que ver la pared de mensaje en el fondo de la
forma de Libro de la Biblioteca, y cambios al Título y campos de Fecha de la Liberación
tendrían que ser logged encima lo.

Cómo trabaja...
El Hablar añadirencima (el correo nombre técnico) proporciona el correo.Modelo de
hilo para utilizar en otros modelos empresariales como mixin clase. Nuestros primeros
pasos son para añadir la dependencia de módulo y para tener la biblioteca.Módulo de
libro para heredar características de él.

Entre otras cosas, el seguidor_de mensaje_ids y mensaje_ids los campos están


añadidos para almacenar la lista adepta y relacionó mensajes. Estos tendrían que ser
añadidos a la vista de forma, utilizando los seguidores_de correo e hilo_de correo
especial widgets.

278
Capítulo 12

También añadimos el opcionales _descriptatributo de ión a la clase del modelo. Está


utilizado por algunos de los mensajes de seguir, como Libro de Biblioteca creó, y
inappropriately mensajes de exhibición como Hilo de Email está creado si no
explícitamente definió. Después de addon instalación, el nombre de exhibición tsombrero'll
ser utilizado también puede ser puesto en Encuadres | Modelos | de Estructura de Base
de datos | Técnicos, en el campo de Descripción del Modelo.
El correo.Modelo de hilo puede mantener la pista de cambios hizo a un documento,
posting les tan mensajes en la pared de mensaje. Para este, justo necesitamos añadir
visibilidad_de pista=Cierta (o cualquier valor cierto) en los campos para seguir.
Por default, estos son posted notas tan internas, significando que ninguno mensajes de
email están provocados.

Versión diferente 8.0, en versión 9.0 el cambió los valores están


almacenados en la base de datos, en el
correo.Siguiendo.Modelo de valor. Esto es accesible en el cliente
de web en Encuadres | el email | Técnico que | Sigue Valores.
Esto puede ser útil para informar o auditoría.

Los tipos de mensaje se apellidan Subtipos. El módulo de correo viene con dos subtipos:
discussion mensajes y notas internas. El primero puede provocar notificaciones de email y es
visible a todos los seguidores. El segundo un no provoca notificaciones y sólo puede ser visto por
usuarios en el grupo de seguridad del Empleado. Podemos poner el subtipo cuándo posting
messages utilizando su XML IDs. Para estos dos, el correspondientes XML IDs es
mail.mt_comentario y
mail.mt_Nota.

El subtipo para los mensajes de seguir puede ser cambiado por el _subtipo_de pista()
método.
Recibe un diccionario con los nombres de campo seguidos con changes, y sus valores antes
de los cambios estuvieron hechos. Está esperado para regresar una cuerda con el XML ID
del subtipo para utilizar. Los subtipos proporcionados por el correo addon no necesita el
sufijo de módulo, así que podemos utilizar justos mt_comentario para mensajes de
discusión. Si ningúns pecific el subtipo está regresado, los mensajes utilizarán el default
mt_subtipo de nota.

Los seguidores pueden suscribir a subtipos diferentes, así que son capaces de escoger
cuándo para ser notificados.
Por ejemplo, el Proyecto addon añade subtipos como etapa de cambio de la Tarea o la
tarea es b cerró. Con _subtipo_de pista() , podemos detectar tales acontecimientos e
informarles a través de mensajes con el subtipo apropiado. Dentro de aquel método, self
hace disponible el recordsets implicó en el escribir operación, de modo que subtipos de
mensaje distinto pueden ser seleccionados based en valores récord arbitrarios.

Allí ha más...
Posting Los mensajes pueden ser hechos utilizando el método siguiente:
obj.Correo_de mensaje(texto="de Cuerpo del cuerpo",
Tema="subject", subtipo="mt_ nota")

El subject y el subtipo es opcional.

279
Automatización y Workflows

Los seguidores pueden ser cualesquier socios o canales de mensaje. Para añadir
seguidores, uso el siguiente:

obj.El mensaje_suscribe(socio_ids=..., canal_ids=..., subtipo_


ids=[])

El subtipo_ids el argumento es opcional, y te dejas para suscribir subtipos concretos. Si


no proporcionado, el defaults definió en los subtipos serán utilizados.
A veces queremos añadir un usuario como adepto. Un usuario es también un socio, así que
usuario.Socio_ id tendría que ser utilizado para este. Aun así, el método concreto siguiente
es también proporcionado para este:
obj.El mensaje_suscribe_usuarios(usuario_ids, subtipo_ids=[])

Es razonable de esperar para ser capaz a mensajes de correo o seguir documentos incluso
si el usuario conectado tiene ningún escribir acceso a ellos. Lógica de seguridad especial
está implementada para dejar esto, y estos particular las operaciones están actuadas con
el usuario de Administrador, a través del sudo() ORM método.
Subtipos de mensaje pueden ser dirigidos en los Encuadres carta superior, por navigating a
la carta | de Subtipos | de Email Técnica elemento. Allí podemos inspeccionar los subtipos
de existir y customize les. La descripción es el texto mostrado en el mensaje, y el Default el
campo indica si el subtipo está suscrito por default para los seguidores nuevos.
Los subtipos apoyan un mecanismo de herencia. Es, por ejemplo, utilizado por proyectos
para dejar el followers a automáticamente suscribir acontecimientos en tareas y asuntos,
como la tarea Abrió. Esto está hecho utilizando los campos en el área de Suscripción del
Coche del subtipo:
fElpadrees el subtipo relacionado para ser automáticamente suscribió.
Paraproyecto.Tarea de proyecto Abrió, esto sería el proyecto
.Tarea de tarea Abrió.
fCampo de relaciónes el campo en el modelo relacionado para utilizar.
Paraproyecto.Subtipode tarea,esto es proyecto _id, para el Proyecto
para heredar suscripción de.
Odoo También apoya un indicador de Acción de la Necesidad, espectáculon en el elemento
de carta, para señalar aquella acción está requerida en un número de elementos. Por
ejemplo, está utilizado por el correo addon para mostrar el número de unread mensajes.
Para utilizarlo, nuestro modelo también tendría que heredar ir.needaction_mixin, y el
_needaction_ el ámbito_consigue() el método tendría que ser extendido. Es un
@api.Modelo método estático, significando que no actúa a un recordset. Está esperado
para regresar una expresión de ámbito para soler identificar los elementos que necesitan
acción.
Cuando un ejemplo, para señalar que elementos con un Bloqueados Kanban acción de
necesidad estatal, utilizaríamos el siguientes:
def _needaction_El ámbito_consigue(self):
Regreso [('kanban_estatal', '=', 'bloqueado')]

280
Capítulo 12

Utilizando acciones de servidor de código de


Pitón
Acciones de servidor tienen muchos escribe disponibles, pero ejecutando arbitrary código
de Pitón es seguramente el más flexible un. Utilizado sabiamente, pueda proporcionar
usuarios de poder con la capacidad para implementar reglas empresariales adelantadas de
la interfaz de usuario, sin la necesidad de crear concreta addon módulos para instalar
aquel código.
Demostraremos utilizar este tipo de acciones de servidor por implementar un
aquello envía notificaciones de recordatorio a los seguidores de una tarea de
Proyecto.

Preparándose
Necesitaremos un Odoo caso con la aplicación de Proyecto instalada.

Cómo para hacerlo...


Para crear y probar un Python acción de servidor del código, seguir estos pasos:

1. Crear una acción de servidor nueva: En los Encuadres carta superior,


seleccionar las Acciones | de Servidor | de Acciones Técnicas elemento de
carta, y clic en el Crear botón en la parte superior de la lista récord.
2. Llena fuera de la forma de Acción del Servidor with los valores siguientes:
‰‰ Nombre de acción: Envía
‰‰
Recordatorio

‰‰
Modelo de base: Tarea
Acción para Hacer: Ejecuta Código
de Pitón

3. En el área de texto de código de Pitón, sacar el default texto y reemplazar él con el


siguiente:
Si no obj.Fecha límite_de fecha:
Levanta Aviso('Task tiene ninguna fecha
límite!') Fecha límite_dt =
datetime.datetime.strptime(
obj.Fecha límite_de fecha, '%Y-%m-%d')
Fecha límite = de delta_dt.Fecha() -
datetime.Fecha.Hoy() delta = de días.Días
Si días==0:
msg = 'La tarea es prevista
hoy.' elif Días < 0:
msg = 'La tarea es %d día(s) tarde.' %
abs(Días) más:
msg = 'La tarea será prevista en %d día(s).' % Días
obj.Correo_de mensaje(msg, el tema= esminder', el subtipo=
soyt_comentario')

281
Automatización y Workflows

4. Salvar la Acción de Servidor y el clic encima Añaden en el soymena' Botón, en


el derecho superior, a make lo disponible en el más botón de la tarea de
Proyecto.
5. Ahora clic en el Proyecto carta superior y seleccionar el elemento | de carta de
Tareas de Búsqueda. Elegir una tarea aleatoria, puesto una fecha de fecha límite
encima lo, y entonces probar el Enviar opción de Recordatorio en el Más botón.

Cómo trabaja...
El Create receta de acciones del servidor proporciona una explicación detallada encima
cómo para crear una acción de servidor en general. Para este tipo particular de acción,
necesitamos elegir el Ejecutar opción de Código de la Pitón y entonces escribir el código
para correr el área de texto.
El código puede haber multiple líneas, cuando es el caso en nuestra receta, y corre en un
contexto que tiene referencias disponibles a objetos como el objeto récord actual o el
usuario de sesión. Las referencias disponibles está descrito en el Crear receta de acciones
del servidor.
El código utilizado computes el número de días de la fecha actual hasta la fecha de fecha
límite, y utiliza que para preparar un mensaje de notificación apropiado. La última línea el
real posting del mensaje en la pared de mensaje de la tarea. El subtipo=
soyt_comentario' el argumento es needed para notificaciones de email para ser
enviados a los seguidores, justo gustar cuándo utilizamos el botón de Mensaje Nuevo. Si
ningún subtipo está dado, mt_la nota está utilizada como default, posting una nota
interna sin notificación, como si utilizamos el Registro un botón de nota interno.

ThAntes de es más...
Acciones de servidor de código de pitón son un recurso potente y flexible , pero tiene algunas
limitaciones compararon al hechos de encargo addon módulos.
Desde el código de Pitón está evaluado en tiempo corrido, en caso de un error el stack el
rastro no es tan informativo und lo puede ser más duro de depurar. Es también no posible
de insertar un breakpoint en el código de una acción de servidor que utiliza las técnicas
mostradas en Capítulo 7, Depurando y Testaje Automatizado, así que depurando
necesidades de ser hechas por utilizar logging declaraciones. Otra preocupación es, cuándo
intentando seguir abajo la causa de un comportamiento en código de módulo, puedes
perder aquello; es probablemente causado por un servidor sction.
Cuándo llevando a cabo un uso más intensivo de acciones de servidor, podemos conseguir
interacciones complejas, así que está aconsejado para planear properly y mantenerles
organizó.
282
Capítulo 12

Utilizando automatizó acciones


puntualmente condiciones
Automatizó las acciones pueden soler automáticamente acciones de gatillo basaron
puntualmente condiciones. Les podemos utilizar a automáticamente actuar alguna
operación enr ecords aquello conoce criterios seguros y lograr condición de tiempo.
Cuando un ejemplo, podemos provocar una notificación de recordatorio para tareas de
Proyecto una víspera su fecha límite, si tienen cualquiera. Dejado es ver cómo esto
puede ser hecho.

Preparándose
Para seguir esta receta, necesitaremos tener ambos la aplicación de Administración del
Proyecto y las Reglas de Acción Automatizadas addon ya instalados, y tener el Modo de
Desarrollador activó. También necesitaremos la acción de servidor creada en la Pitón de
Utilizar receta de acciones de servidor de código.

Cómo para hacerlo...


Para crear una acción automatizada con una condición cronometrada en tareas, seguir estos
pasos:

1. En los Encuadres carta superior, seleccionar la Automatización | Técnica |


Automatizó elemento de carta de las Acciones, y prensa en el Crear botón.
2. Llena fuera de la información básica en el Automatizó forma de Acciones:
‰‰ Nombre de regla: Fecha límite
‰‰ Notificación Cercana Modelo de
‰‰ Documento Relacionado: Tarea
Bajo el tabulador de Condiciones, para Cuándo para Correr, selecciona Basado
puntualmente Condición

3. Para poner los criterios récord, en la caja de texto de campo de Filtro, justo después
del Seleccionar Reenlace de cordones, puesto una expresión de ámbito válida:
[('fecha límite_de fecha', '!=', Falso), ( estage_id.Pliegue',
'=', Falso)]. Cuándo cambiando a otro campo, información en el número de los
registros que conocen los criterios está actualizado, y el Seleccionar cambios de
enlace de los Registros para Cambiar Selección. Por clicking encima lo podemos
comprobar la lista de registros de los registros que conocen la expresión de ámbito.
283
Automatización y
Workflows

4. Para poner la condición de tiempo, encima Fecha de Gatillo selecciona el campo


para utilizar, Fecha límite, y poner el Retraso After Fecha de Gatillo a -1 Días.
284
Capítulo 12

5. En el tabulador de Acciones, debajo acciones de Servidor para correr, el clic encima


Añade un elemento y elegir Enviar Recordatorio de la lista que tendría que haber
sido creado anteriormente. Si no, podríamos ahora también crear la acción de
servidor para correr utilizando el Crear botón.

6. El clic encima Salva para salvar la acción automatizada. Actuar los pasos siguientes
para probarlo fuera:

1. Va al Proyecto carta superior, Tareas | de Búsqueda, y poner un deadline


encima alguna tarea con una fecha antiguamente.
285
Automatización y Workflows

2. Va a los Encuadres carta superior, a la Automatización | Técnica |


Planificó elemento de carta de las Acciones, encontrar la acción de Reglas
de Acción de Control en la lista, abre su forma view, y prensa en el Corrido
Manualmente botón, en la parte superior dejó. Estas fuerzas
cronometraron automatizó acciones para ser comprobadas ahora. Nota que
esto tendría que trabajar en un nuevamente creado demo base de datos,
pero no podría trabajar así en una base de datos de existir.

3. AgaEn ir al Proyecto carta superior y abrir la misma tarea tú anteriormente


puesto una fecha de fecha límite a. Control el tablero de mensaje abajo;
tendrías que ver la notificación generada por la acción de servidor provocada
por nuestra acción automatizada.

Cómo trabaja...
Acción automatizadas acto en un Modelo, y puede ser provocado cualquiera por
acontecimientos o por condiciones de tiempo. Los primeros pasos son para poner
el Modelo y Cuándo para Correr valores.
Ambos métodos pueden utilizar un filtro para angostar abajo los registros elegibles de actuar la
acción encima. Podemos utilizar un ámbito expression para este. Puedes encontrar detalles
encima escribiendo expresiones de ámbito en Capítulo 8, Backend Vistas. Alternativamente,
puedes crear y salvar un filtro encima tareas de proyecto, utilizando las características de
interfaz del usuario, y entonces copia aquí el ámbito automáticamente generado expression,
seleccionando él de la selección de Conjunto basada en una lista de filtro de la búsqueda.
La expresión de ámbito utilizamos selecciona todos los registros con una Fecha límite no vacía
fecha, en una etapa donde la bandera de Pliegue no es comprobada. Las etapas sin la bandera
de Pliegue están consideradas para ser trabajando en progreso. De este modo, evitamos
provocar notificaciones en tareas que es en el Hecho,
Cancelado, o Cerró etapas.

286
Capítulo 12

Entonces tendríamos que definir la condición de tiempo: el campo de fecha para utilizar y
cuando en cronometrar la acción tendría que ser provocada. El periodo de tiempo puede ser
en minutos, horas, días, o meses, y el número de periodos puede ser positivo, para tiempo
después de la fecha, o negativo, para tiempo antes de la fecha. Cuándo utilizando un
periodo de tiempo en días, podemos proporcionar un Calendario de Recurso que define los
días laborables, y la cuenta de día lo utilizará.
Estas acciones están comprobadas por la Acción de Control Gobierna trabajo planificado.
Nota que por default está corrido cada cuatro horas . Esto es apropiado para acciones que
trabajo en los días o escala de meses, pero si necesitas acciones que trabajo en la hora o
minuto timescales, necesitas cambiar el intervalo de correr a un valor más pequeño.
Las acciones serán provocadas para registros que conocer todos los criterios y de quién
fecha de provocar condición (fecha de campo más el intervalo) es después de la última
ejecución de acción. Esto es con objeto de evitar repetidamente provocando la misma
acción. Y esto es por qué manualmente corriendo la acción de preceder trabajará en una
base de datos donde la acción planificada no fue todavía provocado, pero no podría
trabajar inmediatamente en una base de datos where sea ya corrido por el scheduler.
Una vez una acción automatizada está provocada, el tabulador de Acciones te dices qué
tendría que pasar. Esto puede ser una lista de acciones de servidor, haciendo cosas como
cambiar valores en el registro, posting notificaciones, enviando fuera de e-mails, y tan
encima.
Además, dos operaciones especiales son disponibles. Pone Responsable espera el Modelo
de objetivo para tener un usuario_id campo y pone su valor cuándo la acción está
provocada. Añade los seguidores da una lista de socios para ser añadidos a los seguidores
récord.

Allí ha más...
Estos tipos de automatizó las acciones están provocadas una vez una condición de tiempo
segura está logrado. Esto no es igual tan regularmente repitiendo alguna acción mientras
alguna condición es todavía cierta. Por ejemplo, una acción automatizada no sería capaz de
posting un recordatorio todos los días después de la fecha límite ha superado.
Este tipo de la acción en cambio puede ser actuada por Planificó Acciones, almacenados
en el ir.cron Modelo. Aun así, planificó las acciones no apoyan acciones de servidor;
sólo pueden llamar un existiendo method de un objeto de modelo. Tan, para implementar
una acción hecha de encargo, necesitamos escribir un addon el módulo que añade el
método de Pitón subyacente.
Para referencia, el nombre técnico para el Automatizó Modelo de Acciones es base
.Acción.Regla.
287
Automatización y Workflows

Utilizando automatizó acciones


encima condiciones de
acontecimiento
Las aplicaciones empresariales proporcionan sistemas con registros para operaciones
empresariales, pero es también esperado para apoyar el negocio dinámico gobierna aquello es
concreto a los casos de uso de la organización.
Talla estas reglas ena hechos de encargo addon los módulos pueden ser inflexible y
fuera del lograr de usuarios funcionales. Automatizó las acciones provocaron por
condiciones de acontecimiento pueden puente este vacío y proporcionar una
herramienta potente para automatizar o aplicar los procedimientos de organización.
Cuando un ejemplo, aplicaremos una validación encima tareas de Proyecto tal que
sólo el Director de Proyecto puede cambiar Tareas a la etapa Hecha.

Preparándose
Para seguir esta receta, necesitarás tener la aplicación de Administración del Proyecto
ya instalada. También necesitamos tener el Modo de Desarrollador activó. Si no es,
activa él en el Odoo Aproximadamente diálogo.

Cómo para hacerlo...


Para crear una acción automatizada con una condición de acontecimiento en tareas, seguir
estos pasos:

1. En los Encuadres carta superior, seleccionar la Automatización | Técnica |


Automatizó elemento de carta de las Acciones, y prensa en el Crear botón.
2. Llena fuera de la información básica en el Automatizó forma de Acciones:
‰‰ Nombre de regla: Valida Cerrar Tareas
‰‰ Modelo de Documento relacionado:
‰‰
tabulador de Condiciones de la Tarea
|Cuándo para Correr: Encima Actualización
288
Capítulo 12

3. TÉl encima reglas de actualización te dejan para poner dos filtros récord, antes
de que y después de la operación de actualización. En el Antes texto de campo de
Filtro de Actualización caja, después del Seleccionar enlace de Registros, puesto
una expresión de ámbito válida: [( estage_id.name', '!=', 'Hecho')]. En
la caja de texto de campo de Filtro, puesto el ámbito siguiente: [(
estage_id.name', '=', 'Hecho')], cuando mostrado en el siguiente
screenshot.

4. En el tabulador de Acciones, debajo Acciones de Servidor para Correr, el clic


encima Añade un elemento, y en el diálogo de lista, prensa en el Crear botón to
crea una acción de servidor nueva.
5. Llena fuera de la forma de acción del servidor con los valores siguientes y después
pulsar en el Salvar botón:
‰‰ Nombre de acción: Valida Cerrar Tareas
‰‰ Modelo de base: Tarea
‰‰ Acción para Hacer: Ejecuta Código de Pitón
‰‰ Código de pitón: Enter el siguiente:
Si usuario != obj.Proyecto_id.Usuario_id:
Levanta Aviso('Sólo el Director de Proyecto
puede cerrar Tareas')
289
Automatización y Workflows

El siguiente screenshot muestra el introdujo valores:

6. El clic encima Salva, a save la acción automatizada y probarlo fuera:


1. En una base de datos con demo dato y logged en tan Administrador, va
al Proyecto clic y carta superiores en el E-Aprendiendo proyecto de
Integración para abrir su tarea Kanban.
2. Entonces prueba arrastrar un de las tareas al Hechos stage columna.
Desde el director de este Proyecto es usuario Demo y estamos
trabajando con el Administrador de usuario, nuestra acción
automatizada tendría que ser provocada, y nuestro mensaje de aviso
está bloqueando el cambio.

Cómo trabaja...
Empezamos por dar un nombre a nuestros iones de actoautomatizados y poniendo el
Modelo trabaja con. Para el tipo de acción, escogemos Encima Actualización, pero el
Encima Creación, Encima Actualización & de Creación, En Deletion, y Basó Encima
opciones de Modificación de la Forma son también posibles.
Luego, tendríamos que definir los filtros para determinar cuándo our la acción tendría que
ser provocada. El Encima acciones de Actualización nos dejan para definir dos filtros: uno
para comprobar antes de que y el otro después de los cambios están hechos al registro.
Esto puede soler expresar transiciones: detectar cuándo unos cambios récord de estatales
Un a estatales B. En nuestro ejemplo, queremos provocar la acción cuándo una tarea no
hecha cambios a la etapa Hecha. El Encima acción de Actualización es el único uno
aquello deja para estos dos filtros; las otras acciones escribe sólo dejar para uno filtra.
290
Capítulo 12

Es hormigade importación para notar que nuestra condición de ejemplo sólo trabajará
correctamente para usuarios de lengua inglesa. Esto es tan porque el Nombre de Etapa es
un translatable campo que puede tener valores diferentes para lenguas diferentes. Tan,
filtros en el translatable los campos tendrían que serun voided o utilizados con cuidado.
Finalmente, creamos y añadir un (o más) acciones de servidor con cualquier queremos
ser hechos cuándo la acción automatizada está provocada. En este caso, escogimos
demostrar cómo para implementar validación hecha de encargo, haciendo uso de un
bacalao de Pitóne acción de servidor que usos la excepción de Aviso para bloquear los
cambios de usuario.

Allí ha más...
En Capítulo 5, Desarrollo de Lado de Servidor Básico, vimos cómo para redefinir el
escribir() métodos de un modelo para actuar acciones oficialmente actualización.
Automatizó acciones enrecor d la actualización proporciona otra manera de conseguir igual,
con algunos beneficios y drawbacks.
Entre los beneficios, es fácil de definir una acción qué está provocado por la actualización
de un almacenó campo computado, el cual es delicado de hacer en código puro. Es también
posible de definir filtros en registros y tener reglas diferentes para registros diferentes, o para
los registros que emparejan diferentes condiciona cuáles pueden ser expresados con
ámbitos de búsqueda.
Pero automatizó las acciones pueden tener las desventajas cuándo comparadas a Pitón código
de lógica empresarial inside módulos. Como preocupación, con pobre planeando esta
flexibilidad rápidamente puede crecer a interacciones complejas, duros de mantener y depurar.
También, el antes y después escribir operaciones de filtro traen algunos elevados, tan para
actuar acciones sensibles esto podría ser un asunto .

Inspeccionando construido-en workflows


Odoo Incluye un construido en workflow el motor utilizó para dirigir flujos de documento
empresarial e interacción. Aun así, este motor ha sido gradualmente reemplazado por Pitón lógica
empresarial y automatizó acciones. Cuando un ejemplo de tsu, uno del más importante workflows
utilizó para ser el enlazando órdenes de ventas, facturas, y entregas, pero desde entonces versión
9.0, ha sido sacado.

Pero, hay unos cuantos workflows todavía utilizado por algunas aplicaciones, tan puede
haber casos donde un desarrollador need para trabajar con ellos. Así que es todavía
pertinente de tener algunos básicos entendiendo de cómo trabajan.
La aplicación de Campañas del Marketing todavía utiliza un sencillo workflow, y lo
utilizaremos para proporcionar esta visión general breve encima les.

Preparándose
Necesitaremos un Odoo instance con demo dato y la Campaña de Marketing addon el módulo
instalado (no que no es una aplicación). También necesitamos tener el Modo de
Desarrollador activó. Si no es, activa él en el Odoo Aproximadamente diálogo.
291
Automatización y Workflows

Cómo para hacerlo...


Para inspeccionar el workflow definió en un modelo, seguir estos pasos:

1. Abierto la Automatización de Ventaja carta superior. Dependiendo de las


aplicaciones has instalado, en cambio pueda ser Marketing nombrado. Clic en un
registro en la lista de Campañas para abrir su vista de forma.

2. Abierto el Depurar carta (el icono de Bicho en el lado derecho de la barra superior) y
escoger la Impresión Workflow opción. Esto generará un documento de PDF con un
graph de la campaña workflow, mostrando en un fondo rojo el workflow nodo elcur
documento de alquiler es en.

292
Capítulo 12

3. Otra vez en el Depurar carta, seleccionar el Editar Workflow opción. Esto navigate al
Workflow Vista de lista filtrada por el actual workflow. Clic en el workflow línea en la
lista para abrir e inspect su definición.

4. Workflows Tiene un Tercer modo de Vista, el esquema. Clicking En el Tercer tipo de Vista
icono, en el derecho superior después de la vista de forma, podemos ver el workflow
definición en un esquema.
El esquema también deja editar: doble click en los nodos para editar Actividades y
en las líneas para editar Transiciones.
293
Automatización y Workflows

Cómo trabaja...
El workflow las definiciones están almacenadas en el workflow modelo, y es también
reachable a través del Settings carta superior, y navigate a Técnico | Workflows
elemento de carta.
Su definición tiene Actividades. Los nodos o workflow estados, y Transiciones , definiendo
cuándo un workflow el estado actual tendría que mover a otro nodo.
Las transiciones a menudo dependen de un workflow Signal para ser provocados. Una
manera común de provocar un workflow la señal es a través de botones de forma. Los
botones apoyan un tipo="workflow" atributo para este.
Existiendo workflows es customizable: podemos editar o añadir actividades, y podemos
cambiar el
Transiciones connecting les. Sencillo customizations normalmente implica editar una
transición. En el workflow esquema, doble clicking una flecha de transición trae arriba de su
vista de forma. Allí nosotros rewire el workflow por modificar Actividad de Destino,
añadiendo Condición con una Pitón expressiencima para evaluar, o utilizando el grupo
Requirió para limitar la transición para ser provocada sólo por usuarios en un grupo de
seguridad seguro.

Ve también
f La documentación oficial proporciona más detalles sobre workflow definiciones:
https://www.odoo.com/documentation/9.0/reference/workflows.
html.
294
13
Servidor de
web
Desarrollo
Ent su capítulo, cubriremos los temas siguientes:

f Haciendo un camino accesible de la red que


f Restringe acceso a web los caminos accesibles
f que Consumen los parámetros pasaron a
f vuestro handlers Modificando un existiendo
f handler
Utilizando el RPC API

Introduction
Introduciremos el basics de la parte de servidor de la web de Odoo en este capítulo. Nota que
esto cubre las piezas fundamentales. Para funcionalidad de nivel alto, tendrías que referir a
Capítulo 14,
Desarrollo de Sitio web del CMS.

Todo de Odoo petición de web que maneja is conducido por la biblioteca de Pitón werkzeug
(http:// werkzeug.pocoo.org). Mientras la complejidad de werkzeug es
mayoritariamente escondido por Odoo conveniente wrappers, es un interesante leído para
ver cómo trabajo de cosas bajo el capote.

Marca un camino accesible de la red


En esta receta, veremos cómo para hacer un URL del http de
forma://yourserver/camino1/camino2 accesible a usuarios. Esto tampoco puede ser
una página web o un camino que regresa arbitrario data para ser consumido por otros
programas. En el caso último, normalmente utilizarías el JSON formato para consumir
parámetros y para ofrecer vuestro dato.

295
Desarrollo de Servidor de la web

Preparándose
Haremos uso de la biblioteca.Modelo de libro de Capítulo 4, Application Modelos, tan
en caso no has hecho tan todavía, grab su código para ser capaz de seguir los ejemplos.
Queremos dejar cualquier usuario a consulta la lista llena de libros. Además, queremos
proporcionar la misma información a programas vía un JSON petición.

Cómo para hacerlo…


Necesitaremos añadir controladores, los cuales van a una carpeta llamó controladores
por convención:

1. Añadir unos controladores/main.py archivo con la versión de HTML de nuestra


página:
De openerp http de importación
De openerp.Petición de importación del http

La clase Principal(http.Controlador):
@Http.Ruta('/mi_módulo/reserva', tipo='http',
auth='ninguno') def libros(self):
Petición = de
registros.env['Biblioteca.Libro'].sudo().Búsqueda([])
resultado = '<html><mesa><de cuerpo><tr><td>'
Resultado += '</td></tr><tr><td>'.Une(

registros.mapped('Nombre'))

Resultado += '</td></tr></cuerpo></de
mesa></html>' resultado de regreso

2. Añadir una función para servir la misma información en el JSON formato:


@Http.Ruta('/mis_libros/de módulo/json',
tipo='json', auth='ninguno')
def Libros_json(self):
Petición = de registros.env['Biblioteca.Libro']\
.sudo().Búsqueda(
[]) regresa
recordones.Leído(['nombre'])

3. Añadir los controladores de


archivo/__init__.py: De . La
importación principal

4. Añade controladores a vuestro


__init__.py addon: De . Controladores
de importación
296
Capítulo 13

Después de retomar vuestro servidor, puedes visitar /mis_libros/de módulo en vuestro


navegador y conseguir presentado con una lista plana de nombres de libro. Para probar el
JSON-RPC parte, tendrás que oficio un JSON petición. Una manera sencilla de hacer que
sería utilizar la línea de orden siguiente para recibir la producción en la línea de orden:
Rizo -i -X CORREO -H "Contenido-Type: aplicación/json" -d
"{}" \ localhost:8069/mis_libros/de módulo/json

Si consigues 404 errores al llegar a este punto, probablemente tienes más de una base de
datos disponible en vuestro caso. En este caso, es imposible para Odoo para determinar qué
base de datos está significada a serve la petición. Uso el --db-
filtra='^yourdatabasename$' parámetro para forzar que utiliza la base de datos exacta
instalaste el módulo en. Ahora el camino tendría que ser accesible.

Cómo trabaja…
Las dos partes cruciales aquí son que nuestro controlador está derivado de openerp .Http.
Controlador y que los métodos utilizamos para servir el contenido está decorado con
openerp. Http.Ruta. Heredando de openerp.Http.El controlador registra el
controlador con Odoo sistema de encaminamiento en una manera similar como modelos
está registrada, por heredar de openerp. Modelos.Modelo; también, el controlador
tiene un meta clase que cuida de este.
En general, los caminos manejaron por vuestro addon tendría que empezar con vuestro addon
nombre para evitar enfrentamientos de nombre. Naturalmente, si extiendes algunos addon
funcionalidad, utilizarás este addon nombre.

openerp.Http.Ruta
La ruta decorator nos dejo para decir Odoo que un método es para ser la web accesible en primer
lugar, y el primer parámetro determina en qué camino es accesible. En vez de una cuerda,
también puedes pasar una lista de cuerdas en caso utilizas la misma función para servir caminos
múltiples.

El argumento de tipo defaults a http y determina qué tipo de petición es para ser servido.
Mientras estrictamente hablando JSON es HTTP, declarando la segunda función cuando
tipo='json' vida de marcas mucho más fácil, porque Odoo entonces maneja
conversiones de tipo él.
No se preocupa sobre el auth parámetro por ahora, sea dirigido en la receta Restringe
acceso a web caminos accesibles en este capítulo.

Valores de regreso
Odoo tratamiento de las funciones' valores de regreso is determinó por el argumento de
tipo de la ruta decorator. Para escribe='http', normalmente queremos entregar algún
HTML, así que la primera función sencillamente regresa una cuerda que lo contiene. Una
alternativa es para utilizar petición.Marca_
Respuesta(), el cual da controlas encimat él encabezamientos para enviar la respuesta.
Tan, para indicar cuándo nuestra página estuvo actualizada último, podríamos cambiar la
última línea en libros() a:
Petición de regreso.Respuesta_de
marca( resultado, [

297
Desarrollo de Servidor de la web
('Último-modificado', email.utils.formatdate(
(
fields.Datetime.De_cuerda( petición.env['Biblioteca.Libro'].sudo()

.Búsqueda([], orden='escribir_fecha desc', límite=1)


.Escribe_fecha) -
datetime.datetime(1970, 1, 1)
).Segundos_totales
(),
usegmt=Ciertos)),
])

Este código envía un Último-encabezamiento modificado junto con el HTML


generamos, diciendo el navegador cuándo la lista estuvo modificada por última vez.
Extraemos esta información del escribir_campo de fecha de la
biblioteca.Modelo de libro.

En orden para la fragmento de preceder para trabajar, tendrás que añadir algunas
importaciones en la parte superior del file:
Importación de
email de la
importación
datetime
De openerp campos de importación

También puedes crear un objeto de Respuesta de werkzeug manualmente y regreso


que, pero hay poco beneficio para el esfuerzo.

Generando HTML manualmente es bueno para propósitos de


manifestación, pero tienes que nunca esto en código de producción.
Siempre plantillas de uso, cuando demostrados en Capítulo 14,
Desarrollo de Sitio de Web de CMS, receta QWeb, y regresarles por
llamar petición.render().
Esto te dará localization para libre y hace vuestro código mejor por
separar lógica empresarial de la capa de presentación. También, las
plantillas proporcionan tú con funciones para huir dato antes de
outputting HTML. El código de preceder es vulnerable de cruzar-sitio-
scripting ataques si un usuario dirige resbalar una etiqueta de
guión al nombre de libro, paraex ample.

Para un JSON petición, sencillamente regresar la estructura de dato quieres entregar encima al
cliente; Odoo cuida de serialization. Para este para trabajar, te tendrías que restringir al dato
escribe aquello es
JSON serializable, Los cuales son aproximadamente diccionarios, lists, cuerdas, flotadores y
enteros.
298
Capítulo 13

openerp.Http.Petición
El objeto de petición es un objeto estático refiriendo a la petición actualmente manejada,
el cual contiene todo necesitas tomar acción útil. La mayoría de importante es el pro perty
petición. env, El cual contiene un Entorno objeta cuál es justo igual tan en
self.env Para modelos. Este entorno está atado al usuario actual, el cual es ninguno en
el ejemplo de preceder porque utilizamos auth='ninguno'. La carencia de una usuaria es
también por qué tenemos que sudo() todo nuestras llamadas a métodos de modelo en el
código de ejemplo.
Si estás utilizado a desarrollo de web, esperarás la sesión que maneja, el cual es
perfectamente correcto. Petición de uso.Sesión para un OpenERPSession objeto (cuál es
bastante un delgado wrapper
Alrededor del Sessiencima objeto de werkzeug ), y petición.Sesión.sid Para acceder
la sesión ID. Para almacenar valores de sesión, justo tratar petición.Sesión como
diccionario:
Petición.Sesión['hola'] = 'mundo'
petición.Sesión.Consigue('hola')

Nota que almacenando el dato en la sesión es nod ifferent de


utilizar variables globales. Uso él sólo si tienes que — aquello es
normalmente el caso para multi acciones de petición como un
checkout en el módulo_de venta del sitio web. Y también en
este caso, maneja toda funcionalidad respecto de sesiones en
vuestros controladores, nunca en vuestros módulos.

Allí ha más…
La ruta decorator puede tener algunos parámetros extras para personalizar su
comportamiento más allá. Por default, todos métodos de HTTP están dejados, y Odoo
intermingles los parámetros pasaron. Utilizando los métodos de parámetro, puedes
pasar una lista de métodos para aceptar, el cual normalmente sería uno de cualquier
['CONSEGUIR'] o ['CORREO'] .

Para dejar peticiones de origen de la cruz (bloque de navegadores AJAX y algunos otros tipos
de peticiones a ámbitos otro que donde el guión estuvo cargado de para seguridad y razones
de intimidad), puestos el cors parámetro a * para dejar peticiones de todos los
orígenes, o algunos URI para restringir peticiones a unos originando de este URI. Si este
parámetro es unset, el cual es el default, el Acceso-Control-Dejar-encabezamiento
de Origen no es puesto, dejando tú con el browser comportamiento estándar. En nuestro
ejemplo, podríamos querer puestos lo encima /mis_libros/de módulo/json para
dejar los guiones estiraron de otros sitios web que acceden la lista de libros.
Por default, Odoo protege tipos seguros de peticiones de un ataque sabido cuando
cruz-site petición forgery por pasar un token a lo largo de en cada petición. Si quieres
apagar aquello, puesto el parámetro csrf a Falso , pero nota que esto es una idea
mala en general.
299
Desarrollo de Servidor de la web

Ve también
Si te múltiplo anfitrión Odoo databases en el mismo caso y cada base de datos tiene web
diferente caminos accesibles encima posiblemente nombres de ámbito múltiple por base de
datos, las expresiones regulares estándares en el --db-parámetro de filtro no podría
ser bastante para forzar la base de datos correcta para cada ámbito. En aquel caso, uso el
módulo comunitario dbfilter_de_encabezamiento de https://github.com/oca/server-
tools para configurar los filtros de base de datos en el proxy nivel.
Para ver cómo utilizando las plantillas hace modularity posibles, ver la receta Modifica
un existiendo handler más tarde en el capítulo.

Restringe acceso a web caminos accesibles


Exploraremos los tres mecanismos de autentificación Odoo proporciona para rutas en esta receta.
Definiremos rutas con diferentes authentication mecanismos para mostrar sus diferencias.

Preparándose
Cuando extendemos código de la receta anterior, también dependeremos de la
biblioteca.Modelo de libro de Capítulo 4, Modelos de Aplicación, así que tendrías que
conseguir su código para proceder.

Cómo para hacerlo…


Define handlers en controladores/main.py:
1. Añadir un camino que espectáculos todos los libros:
@Http.Ruta('/mi_módulo/todo-libros', tipo='http',
auth='ninguno') def todos los _libros(self):
Petición = de
registros.env['Biblioteca.Libro'].sudo().Búsqueda([])
resultado = '<html><mesa><de cuerpo><tr><td>'
Resultado += '</td></tr><tr><td>'.Une(

registros.mapped('Nombre'))

Resultado += '</td></tr></cuerpo></de
mesa></html>' resultado de regreso

2. Añadir un camino que espectáculos todos los libros e indica cuál estuvo escrito por
el usuario actual, si cualquiera:
@Http.Ruta('/mi_módulo/todo-marca/de libros-
mina', tipo='http', auth='público')
def Toda_mina_de marca_de los libros(self):
Petición = de
registros.env['Biblioteca.Libro'].sudo().Búsqueda([])
300
Capítulo 13
Resultado = '<html><mesa><de
cuerpo>' para récord en
registros:
Resultado += '<tr>'
Si récord.Autor_ids & request.env.Usuario.Socio_id:
resultado += '<th>'
Más:
Resultado +=
'<td>' resultado +=
record.name
Si récord.Autor_ids &
petición.env.Usuario.Socio_id: resultado +=
'</th>'
Más:
Resultado +=
'</td>' resultado +=
'</tr>'
Resultado += '</cuerpo></de
mesa></html>' resultado de regreso

3. Añadir un camino que espectáculos los libros del usuario actual:


@Http.Ruta('/mi_módulo/todo-mina/de libros',
tipo='http', auth='usuario')
def Toda_mina_de libros(self):
Petición = de registros.env['Biblioteca.Libro'].Búsqueda([
('autor_ids', 'en',
petición.env.Usuario.Socio_id.ids),
])
Resultado = '<html><mesa><de
cuerpo><tr><td>' resultado +=
'</td></tr><tr><td>'.Une(
Registros.mapped('Nombre'))
Resultado += '</td></tr></cuerpo></de
mesa></html>' resultado de regreso

Con este código, los caminos /mi_módulo/todos los _libros y


/mi_módulo/todo_reserva/ mirada_de mina de la marca igual para unauthenticated
usuarios, mientras un logged en el usuario ve sus libros en una fuente intrépida en el
camino último. El camino /mi_módulo/todo-mina/de libros no es accesible en
absoluto para unauthenticated usuarios. Si intentas acceder él sin ser autenticado, serás
redirigido a the login pantalla para hacer tan.

Cómo trabaja…
La diferencia entre métodos de autentificación es básicamente qué puedes esperar del
contenido de petición.env.Usuario .
Para auth='ninguno', el registro de usuario es siempre vacío, incluso si un usuario
autenticado es accessing el camino. Uso esto si quieres servir contenido que tiene ninguna
dependencia en usuarios, o si quieres proporcionar base de datos funcionalidad agnóstica
en un servidor módulo ancho.

301
Desarrollo de Servidor de la web

El valor auth='público' conjuntos el usuario récord to un usuario especial con XML ID


base.Usuario_público, para unauthenticated usuarios, y al registro del usuario para
autenticó unos. Esto es la elección correcta si quieres funcionalidad de oferta a ambos
unauthenticated y autenticó usuarios, mientras el autenticados unos consiguen algunos
extras , cuando demostrados en el código de preceder.
Uso auth='usuario' para ser seguro que sólo autenticó los usuarios tienen acceso a qué
tienes para ofrecer. Con este método, puedes ser petición segura .env.Puntos de usuario a
algunos existiendo usuario.

Allí ha más…
La magia para métodos de autentificación pasa en el ir.Modelo de http de la base
addon. Para cualquier valor pasas al auth parámetro en vuestra ruta, Odoo busca una
función llamó _auth_método_<yourvalue> en este modelo, así que puedes fácilmente
customize esto por heredar este modelo y declarando un método que cuida de vuestro
método de autentificación de elección.
Cuando un ejemplo, proporcionamos un grupo de base de método_de
autentificación_usuario qué aplica un actualmente logged en usuario quién es un
miembro del grupo con XML ID base.Usuario_de grupo:
De openerp excepciones de importación, http,
modelos de openerp.Petición de importación
del http

Clase
IrHttp(modelos.Modelo):
_hereda = 'ir.Http'

def _auth_Usuario_de grupo_de base_de


método(self): self._auth_Usuario_de
método()
Si no pedir.env.Usuario.Tiene_grupo('base.Usuario_de
grupo'): levanta excepciones.AccessDenied()

Ahora puedes decir auth='usuario_de grupo_de la base' en vuestro decorator y


ser seguro que los usuarios que corren esta ruta handler es miembros de este grupo. Con
un poco trickery puedes extender esto a auth='grupos(xmlid1,…)' , la implementación de
este queda como un ejercicio al lector, pero está incluido en el código de ejemplo.

Consume los parámetros pasaron a


vuestro handlers
Es bueno de ser capaz de mostrar contenido, pero es mejor de mostrar contenido a raíz
de alguna entrada de usuario. Esta receta demostrará las maneras diferentes de recibir
esta entrada y reaccionar a él. Cuando en las recetas anteriores, haremos uso de la
biblioteca.Modelo de libro.

302
Capítulo 13

Cómo para hacerlo…


Primero, añadiremos una ruta que espera un tradicional parameter con un libro ID para mostrar
algunos detalla aproximadamente lo. Entonces, haremos igual, pero incorporaremos nuestro
parámetro al camino él:
1. Añadir un camino que espera un libro ID cuando parámetro:
@Http.Ruta('/mi_libro/de módulo_detalla',
tipo='http', auth='ninguno')
def Detalles_de libro(self, libro_id):
Petición = récord.env['Biblioteca.Libro']
.sudo().Explora(int(libro_id))
regreso u'<html><cuerpo><h1>%s</h1>Autores: %s' %
(
record.name, u', '.Une(
récord.Autor_ids.mapped('Nombre')) o 'ninguno',
)

2. Añadir un camino donde podemos pasar el libro ID en el camino:


@Http.Ruta("/mi_modelo/de detalles_de libro/<de módulo(\

'biblioteca.Libro'):libro>", tipo='http',

auth='ninguno')

def Detalles_de libro_en_camino(self,


libro): regreso self.Detalles_de
libro(book.id)

Si señalas vuestro navegador a /mis_detalles/de libro_del módulo?Libro_id=1,


tendrías que ver una página de detalle del libro con ID 1. Si esto no existe, recibirás una
página de error.
El segundo handler te dejas para ir a /mi_libro/de módulo_detalla/1 y ver la
misma página.

Cómo trabaja…
Por default, Odoo (de hecho werkzeug) intermingles con CONSEGUIR y parámetros de
CORREO y les pasa tan argumento de palabra clave a vuestro handler. Tan por
sencillamente declarando vuestra función cuando esperando un parámetro libro
llamado_id, introduces este parámetro tan tampoco CONSEGUIR (el parámetro en el
URL) o CORREO (normalmente pasó de largo formas con vuestro handler cuando acción)
parámetro. Dado que no añadimos un default valor para este parámetro, el runtime
levantará un error si intentas acceder este camino sin poner el parámetro.
Las segundas marcas de ejemplo uso del hecho that en un werkzeug entorno, más los
caminos son virtuales en todo caso. Así que sencillamente podemos definir nuestro camino
cuando conteniendo alguna entrada. En este caso, decimos que esperamos el ID de una
biblioteca.Libro como el último componente del camino. El nombre después del colon es el
nombre de un keyword argumento. Nuestra función se apellidará, con este parámetro pasó tan
argumento de palabra clave. Aquí, Odoo cuida de mirar arriba de este ID y entregando un
explorar récord, el cual naturalmente trabajos únicos si el usuario que accede este camino tiene
permisos apropiados. Given que el libro es un explorar récord, sencillamente podemos
reciclar la función del primer ejemplo por pasar book.id tan libro de parámetro_id para dar
fuera del mismo contenido.
303
Desarrollo de Servidor de la web

Allí ha más…
Definiendo los parámetros dentro del camino es un functionality entregó por werkzeug, el
cual se apellida convertidores. El convertidor de modelo está añadido por Odoo, el cual
también define los modelos de convertidor, aquello acepta una coma lista separada de
IDs y pasa un conjunto récord que contiene aquellos IDs a vuestro handler.
La belleza de convertidores es que el runtime coacciona los parámetros al tipo esperado,
mientras eres por tu cuenta con parámetros de palabra clave normal. Estos están entregados
como cuerdas, y tienes que cuidar de las conversiones de tipo necesarias tú, cuando vistos enel
abeto st ejemplo.

Construido-en werkzeug los convertidores incluyen int, flotador, y cuerda , pero también
más intrincado unos como camino, cualquiera, o uuid . Puedes mirar arriba de su
semantics en http://werkzeug.
pocoo.org/docs/0.11/routing/#builtin-Convertidores.

Ve también
Odoo los convertidores hechos de encargo están definidos en ir_http.py en el módulo
de base y registrado en el _conseguir_método de convertidores de ir.Http . Cuando un
ejercicio, puedes crear vuestro convertidor propio que te dejas para visitar el
/mi_libro/de módulo_detalla/Odoo+página de recetario para recibir los detalles
de este libro (si lo añadiste a vuestra biblioteca antes). La implementación de este
convertidor esi ncluded en el código de ejemplo para esta receta.

Modificar un existiendo handler


Cuándo instalas el módulo de sitio web, el sitio web /de camino/info muestra alguna
información sobre vuestro Odoo caso. En esta receta, nosotros override esto para cambiar
el diseño de esta página de información, pero también para cambiar qué está mostrado.

Preparándose
Instalar el módulo de sitio web e inspeccionar el sitio web /de camino/info. Ahora oficio
un módulo nuevo que depende de sitio web y utiliza el código siguiente.

Cómo para hacerlo…


Tendremos que adaptar el existing plantilla y override el existiendo handler:

1. Override El qweb la plantilla en un archivo llamó plantillas/de vistas.xml:


<?xml Versión="1.0" codificando="UTF-
8"?> <odoo>
<Plantilla id="sitio web_de
espectáculo_info" hereda_id="sitio
web.Sitio web_de espectáculo_info">

304
Capítulo 13
<xpath expr="//dl[@t-
foreach='Aplicaciones']" la
posición="reemplaza">
<Mesa de clase="de la mesa">
<tr t-foreach="Aplicaciones" t-
tan="aplicación"> <th>
<Un t-att-
href="aplicación.Sitio web">
<t t-esc="app.name" /></un>
</th>
<td><t t-esc="Aplicación.Resumen"
/></td> </tr>
</Mesa>
</xpath>
</tempTarde>
</odoo>

2. Override El handler en un archivo llamó controladores/main.py:


De openerp http de importación
De openerp.addons.Sitio web.Controladores.Sitio web de importación
principal

Sitio web de clase(Sitio


web): @http.Ruta()
def Sitio web_info(self):
Resultado = super(Sitio web, self).Sitio
web_info()
resultado.qcontext['Aplicaciones'] = \
resultado.qcontext['Aplicaciones'].Filtrado(
Lambda x: x.name != 'Sitio
web') resultado de regreso

Ahora, cuándo visitando el info página, sólo veremos una lista filtrada de aplicaciones
instaladas, y en una mesa como opposed al original lista de definición.

Cómo trabaja
En el primer paso, nosotros override un existiendo QWeb plantilla. Para descubrir cuál
aquello es, tendrás que consultar el código del original handler. Normalmente, acabe con
la línea de orden siguiente, el cual te dices que necesitas a override template.name:
Petición de regreso.render('template.name', valores)

En nuestro caso, el handler utiliza una plantilla llamó website.info, pero esto uno es
inmediatamente extendido por otra plantilla sitio web llamado.Sitio web_de
espectáculo_info, así que es más conveniente a override este un. Aquí,
reemplazamos la lista de definición que muestra aplicaciones instaladas con una mesa.
Para detalles aproximadamente qué QWeb trabajos de herencia, consulta Capítulo 14,
Desarrollo de Sitio web del CMS.

305
Desarrollo de Servidor de la web

Para override el handler método, tenemos que identificar la clase que define el handler,
Cuál es openerp.addons.Sitio web.Controladores.Principal.Sitio web, en
este caso. Importamos la clase para ser capaz de heredar de él. Ahora nosotros override el
método y cambiar el dato pasó a la respuesta. Nota que lo que el overridden handler los
regresos es un objeto de Respuesta y no una cuerda de HTML, cuando las
recetas anteriores hicieron por el bien de brevity. Este objeto
contiene una referencia a la plantilla para ser utilizada y los
valores accesibles al templato, pero es sólo evaluado en el muy fin de la petición.

En general, hay tres maneras para cambiar un existiendo handler:

fSi utiliza un QWeb plantilla, la manera más sencilla de cambiar es a override la


plantilla.Esto es la elección correcta para diseño changes y cambios de lógica
pequeña.
fQWeb Las plantillas consiguen un contexto pasó, el cual es disponible en la
respuesta como el campoqcontext. Esto es normalmente un diccionario donde
te puede añadir o sacar valores para convenir vuestras necesidades. En el ejemplo
de preceder, filtramos el list de aplicaciones a sólo contener aplicaciones qué
tener un conjunto de sitio web.
fSi el handler recibe parámetros, podrías también preprocess aquellos para
tenerel overridden handler behave la manera quieres.

Allí ha más…
Cuando visto en la sección de preceder, la herencia con controladoras trabaja
ligeramente de manera diferente que herencia de modelo: de hecho necesitas una
referencia a la clase de base y para utilizar herencia de Pitón encima lo.
No olvida para decorar vuestro nuevo handler con el @http.Ruta decorator; Odoo utiliza él
como marcador for cuál los métodos están expuestos a la capa de red. Si omites el decorator,
de hecho haces el handler el camino inaccesible.
El @http.Ruta decorator él behaves de modo parecido a campo declarations: cada valor
tú no puesto será derivado del decorator de la función eres primordial, así que no tenemos
que repetir valores no queremos cambio.
Después de recibir un objeto de respuesta de la función tú override, puedes hacer mucho
más de justo cambiando el QWeb contexto:
f Puedes añadir o sacar HTTP encabezamientos por manipular
respuesta.Encabezamientos.
f Si quieres render una plantilla enteramente diferente, puedes poner
respuesta.Plantilla.
f Para detectar si una respuesta está basada en QWeb en primer lugar, consulta
response.is_qweb.
f El código de HTML resultante es available por llamar respuesta.render().
306
Capítulo 13

Ve también
f Detalles de QWeb las plantillas serán explicadas en Capítulo 14, desarrollo de Sitio web
del CMS.

Utilizando el RPC API


Uno de Odoo las fuerzas es su interoperabilidad , el cual está ayudado por el hecho que
básicamente cualquier funcionalidad es disponible vía JSON-RPC 2.0 y XMLRPC. En esta
receta, exploraremos cómo para utilizar ambos de ellos de código de cliente. Esta interfaz
también te habilitas para integrar Odoo con cualquier otra aplicación. Haciendo funcionalidad
unvailable vía cualquier de los dos protocolos en el lado de servidor está explicado en el hay
más sección de esta receta.
Nosotros consulta una lista de módulos instalados del Odoo caso, de modo que podríamos
mostrar a una lista le gusta el mostrado en la receta anterior en nuestra aplicación propia o
sitio web.

Cómo para hacerlo…


El código siguiente no es significado para correr dentro de Odoo, pero guiones tan sencillos:

1. Primero, nosotros consulta la lista de módulos instalados vía XMLRPC:


#!/usr/Cubo/env pitón2
importación xmlrpclib

db = 'odoo9'
usuario = 'admin'
password = 'admin'
uid = xmlrpclib.ServerProxy( 'Http://localhost:8069/xmlrpc/2/común')\

.Autentica(db, usuario, contraseña, {})


odoo = xmlrpclib.ServerProxy(
'Http://localhost:8069/xmlrpc/2/objeto')
módulos_instalados = odoo.Ejecuta_kw(
db, uid, contraseña, 'ir.Módulo.Módulo', esearch_lee',
[[( estate', '=', 'instalado')], ['nombre']],
{'contexto':
{'lang': 'fr_FR'}})
Para módulo en
módulos_instalados: módulo de
impresión['nombre']

2. Entonces nosotros igual con JSONRPC :


Importación
json
importación
urllib2

db = 'odoo9'
usuario =
'admin'
307
Desarrollo de Servidor de la web
Contraseña = 'admin'

Petición = urllib2.Petición( 'http://localhost:8069/sesión/de


web/autentica',
json.Vertederos({
'jsonrpc': '2.0',

'params': {
'db': db,
'login':
usuario,
'Contraseña': contraseña,
},
}),
{'Contenido-escribe':
'aplicación/json'}) resultado =
urllib2.urlopen(Petición).Leído() resultado
= json.Cargas(resultado)
Sesión_id = resultado[ essult'][
esession_id'] petición = urllib2.Petición(
'Http://localhost:8069/web/dataset/llamada_k
w', json.Vertederos({
'jsonrpc': '2.0',
'params': {
Soyodel': 'ir.Módulo.Módulo',
soyethod': esearch_lee',
'args': [
[( Estate', '=',
'instalado')], ['nombre'],
],
'kwargs': {'Contexto': {'lang': 'fr_FR'}},
},
}),
{
'X-Openerp-Sesión-Id': sesión_id,
'Contenido-escribe':
'aplicación/json',
})
Resultado =
urllib2.urloBolígrafo(petición).Leído()
resultado = json.Cargas(resultado)
Para módulo en resultado[
essult']: módulo de
impresión['nombre']

Ambas fragmento de código imprimirán una lista de módulos instalados, y porque pasan un
contexto que conjuntos la lengua a francés, la lista será en francés si hay traducciones
disponibles.
308
Capítulo 13

Cómo trabaja…
Ambas fragmento llaman la búsqueda de función_leída, el cual es muy conveniente
porque puedes especificar un ámbito de búsqueda en el modelo llamas, pase una lista de
campos quieres ser returned, y recibir el resultado en uno pide. En versiones más viejas
de Odoo, tuviste que llamar búsqueda primero para recibir una lista de IDs y entonces
llamar leído a de hecho leído el dato.
La búsqueda_leída regresa una lista de diccionarios, con las llaves siendo los
nombres del fields pedidos y los valores el dato del registro. El ID campo siempre será
transmitido,
Ningún asunto si lo pediste o no.

Ahora necesitamos mirar en el specifics de los dos protocolos.

XMLRPC
El XMLRPC API espera un usuario ID y una contraseña para cada call, el cual es por qué
nosotros necesita a fetch este ID vía el método autentica en el camino
/xmlrpc/2/común. Si ya sabes el usuario ID, puedes skip este paso.

Apenas sabes el usuario ID, puedes llamar el método de cualquier modelo por llamar
ejecuta_kw en el camino /xmlrpc/2/objeto. Este método espera la base de datos
quieres ejecutar la función encima, el usuario ID y contraseña para autentificación, entonces
el modelo quieres llamar vuestra función encima, y entonces el nombre de la función. El
próximos dos parámetros obligatorios are una lista de argumentos posicionales a vuestra
función, y un diccionario de argumentos de palabra clave.

JSONRPC
No es distraído por la medida del ejemplo de código; aquello es porque la pitón no ha
construido en soporte para JSONRPC. Apenas has envuelto el urllib calls en algún
helper funciones, el ejemplo será tan conciso como el XMLRPC un.
Cuando JSONRPC es stateful, la primera cosa tenemos que hacer es para pedir una
sesión en /sesión/ de web/autentica. Esta función toma la base de datos, el
nombre del usuario, y
Su pasespada.

La parte crucial aquí es que grabamos la sesión ID Odoo creado, el cual pasamos en el
encabezamiento X-Openerp-Sesión-Id a /web/dataset/llamada_kw . Entonces la
función behaves igual cuando ejecuta_kw de; necesitamos pasar un nombre de modelo y
una función a call encima lo, entonces posicional y argumentos de palabra clave.

Allí ha más…
Ambos protocolos te dejan para llamar básicamente cualquier función de vuestros modelos.
En caso no quieres una función para ser disponible vía cualquier interfaz, prepend su
nombre con un underscore – Odoo ganado't expone aquellos funciona tan RPC llamadas.
309
Desarrollo de Servidor de la web

Además, necesitas cuidar que vuestros parámetros, así como los valores de regreso, es
serializable para el protocolo. Para ser seguro, te restringe a valores escalares, dictionaries, y
listas.
Cuando puedes hacer aproximadamente igual con ambos protocolos, es hasta ti cuál para
utilizar. Esta decisión tendría que ser principalmente conducida por qué vuestros soportes de
plataforma más. En un contexto de web, eres generalmente mejor fuera con JSON, porque
Odoo deja JHIJO handlers para pasar un CORS encabezamiento oportunamente (ve la Marca
un camino accesible de la receta de red de este capítulo para detalles). Esto es bastante
difícil con XMLRPC.

Ve también
Los métodos empresariales más interesantes para llamar en los modelos están explicados
en Capítulo 5,
Lado de Servidor básico Lógica Empresarial.
310
14
Sitio web de
CMS
Desarrollo
En este capítulo, cubriremos los temas siguientes:

f Extendiendo CSS y Javascript para el sitio


f web que Crea o modifying plantillas: QWeb
f fragmento de Ofrenda al usuario

Introducción
Odoo Viene con un CMS plenamente presentado el sistema implementado por el sitio web
addon. Algunos funcionalidad de nivel bajo está proporcionada por la web addon, así que si
necesitas mirar arriba código, mantener ambos módulos en mente.

Extendiendo CSS y Javascript para


el sitio web
En esta receta, veremos cómo para añadir hojas de estilo hecho de encargo y Javascript al
sitio web.

Preparándose
Crear un módulo vacío nombró ch13_r01 e instalar él en vuestra base de datos de prueba.
Marca seguro estemo dule depende de el módulo de sitio web, cuando utilizamos algunos
de su funcionalidad.

311
Desarrollo de Sitio web del CMS

Cómo para hacerlo...


Override La plantilla de sitio web principal para inyectar vuestro código:

1. Añadir un archivo llamó plantillas/de vistas.xml Y añadir una vista vacía


override:
<odoo>
<Plantilla id="ventajas_frontend"
heredar_id="sitio
web.Ventajas_frontend">
<xpath expr="." Interior="de
posición"> <!-- Puntos 2 & 3 va
aquí /-->
</xpath>
</Plantilla>
</odoo>

2. Añadir una referencia a vuestro CSS archivo:


<Enlace
href="/ch13_r01/estático/src/css/ch13_r01.cs
s" rel="stylesheet" Texto="de tipo/css"/>

3. Añadir una referencia a vuestro archivo de Javascript:


<Guión
src="/ch13_r01/estático/src/js/ch13_r01.j
s" texto="de tipo/javascript" />

4. Añade algunos CSS código a estático/src/css/ch13_r01.css .


Cuerpo
{
De fondo: amarillo;
}

5. Añade tanme código de Javascript a estático/src/js/ch13_r01.js .


odoo.Define('ch13_r01', función(requiere)
{
var El núcleo =
requiere('web.Núcleo');
alerta(núcleo._t('Hola Mundo'));
Regreso {
// Si creaste funcionalidad para exportar, añadirlo aquí
}
});

Después de actualizar vuestro module, tendrías que ver que Odoo los sitios web tienen un
fondo amarillo y un un poco molesto Hola mundial popup en cada carga de página.
312
Capítulo 14

Cómo trabaja...
En la base de Odoo mentiras de CMS un XML templating el motor llamó QWeb, el cual es
discoussed en detalle en la receta siguiente. Por ahora, es bastante para saber que lo
podemos utilizar para inyectar nodos a existir documentos. En el ejemplo, cambiamos el
sitio web de vista.Ventajas_frontend para enlazar a nuestro CSS y archivos de
Javascript. Esta vista será estiradat o construye todo el HTML para el sitio web, así que
puedes ser seguro vuestro código es disponible encima todas las páginas.
Cuando podemos ser seguro el sitio web de vista.Ventajas_frontend está
estirado dentro de un nodo de cabeza del HTML, sencillamente podemos añadir los
archivos necesitamos y posiblemente ajustar o añadir otro nodes en el elemento de
cabeza también.
Para CSS archivos, asuntos de orden. Tan si necesitas a override un estilo definido en otro
addon, tendrás que cuidar que vuestro archivo está cargado después del archivo original
quieres modificar. Esto puede ser hecho por cualquier ajustando el campo de prioridad de
vuestra vista o directamente heredando del addon vista que inyecta la referencia al CSS.
Para detalles, consultar el Capítulo 8, Backend Vistas, la receta que Cambia existiendo
vistas: herencia de Vista.
Para evitar ordenando asuntos con Javascript, Odoo utiliza un mecanismo muy similar a
RequireJS (http://requirejs.org): En vuestro archivo de Javascript, llamas
odoo.Define(), el cual recibe el namespace quieres definir como el primer argumento, y
una función que contiene la implementación real como el segundo argumento.
El nombre para ser definido tendría que ser vuestro addon nombre. En caso exportas
muchas partes lógicamente diferentes de funcionalidad, definirles en funciones diferentes,
con vuestro addon nombre prepended y separado by puntos para evitar que nombran
conflictos en el futuro. Esto es lo que el módulo de web , el cual define, entre otros,
web.Núcleo y web.Dato . La función de definición recibe sólo un parámetro, requiere,
el cual es una función puedes utilizar para obtener referencias a JavaGuión namespaces
definió en otros módulos o en el núcleo. Uso esto para todas las interacciones con Odoo y
nunca confiar en el global odoo objeto.
Vuestra función propia entonces puede regresar un objeto que señala a las referencias quieres
hacer disponible para otro addons, o nada si hay no tales referencias. Ser lavish con exportador
vuestros objetos propios; pocas cosas son más frustrando que teniendo que saltar a través de
hoops para utilizar algunos existiendo funcionalidad justo porque su desarrollador no molestó
para exportarlo properly. El objeto regresas aquí es lo que otro código consigue cuándo él llama
requerir('yourmodule').

Por convención, vuestros archivos se tendrían que apellidar como vuestro módulo con la
extensión apropiada añadida y vivir en estático/src/css o estático/src/js respectivamente.
Único if vuestros archivos devienen bastante grandes para ser un asunto de mantenimiento tiene
que les partiste arriba a más pequeño chunks.

El requerir el mecanismo hablado aquí es nuevo para Odoo 9.0. En versiones más viejas,
addons tratando necesidad de Javascript para definir una función con el mismo name
cuando el addon en el openerp namespace. Esta función recibe una referencia al caso
actualmente cargado como parámetro, de qué API las funciones son para ser accedidos.
Tan, para upgrade existiendo código, cambio esto a un odoo.Define cláusula e importar los
objetos necesarios vía requerir.

313
Desarrollo de Sitio web del CMS

Allí ha más...
En vez de pasar sencillo CSS a Odoo, puedes también uso de marca de menos
(http://lesscss.org), el cual es una notación de nivel más alta para CSS aquello ayuda
escribes más eficaz CSS código. Ciertamente para bases de código grande, mejore maintainability
mucho. Dado Odoo utiliza esto internamente en todo caso, puedes confiar encima lo siendo
disponible. Tan, para utilizar menos en vez de sencillo CSS, punto justo al menos file en vuestro
elemento de enlace y texto de tipo="del uso/menos" – esto hará Odoo carrera lessc en
vuestro archivo para generar CSS en la mosca sin ti teniendo que hacer cualquier cosa para él.

Creando o modificando plantillas - QWeb


Añadiremos capacidades de sitio web al library addon desarrolló en Capítulo 4, modelos de
Aplicación, y siguiendo. Qué estamos interesar en está dejando usuarios para explorar a
través de la biblioteca y, si son logged en con los permisos apropiados, habilitarles para
editar derecho de contenido del libro de las website interfaz.

Preparándose
Cuando hacemos uso de la biblioteca.Modelo de libro, consigue capítulo 4 código
para mi_módulo. Para comodidad, el código de esta receta contiene una copia de él.

Cómo para hacerlo...


Necesitaremos definir un par de controladores y vistas:

1. Añadir un templcomió que exhibiciones una lista de libros en plantillas/de


libro_de biblioteca_de vistas. xml.
<odoo>
<Plantilla id="libros">
<t t-Sitio web="de
llamada.Sección"> <de
diseño>
Esto es un texto editable antes de la lista de
libros. </Sección>
<t t-foreach="Libros" t-tan="libro">
<Artículo itemscope="itemscope"
itemtype="http://schema.org/book" t-
attf-libro="de fila de la clase-
#{paridad_de libro}">
<h2 t-campo="book.name" clase="col-md-12" />
<t t-si="libro.Liberación_de fecha">
<div Clase="col-md-2" t-att-
dateCreated="libro.Liberación_de
fecha" t-libro="de
campo.Liberación_de fecha" />
</t>

314
Capítulo 14
<ul
Clase="col-md-10">
<li t-foreach="Libro.Autor_ids" t-
tan="autor" itemprop="autor">
<t t-esc="author.name" />
</li>
</ul>
</Artículo>
</t>
<Sección contenteditable="Falso">
Esto es un texto no editable después del list de
libros. </Sección>
</t>
</Plantilla>
</odoo>

2. Añadir un controlador que sirve la lista de libros en controladores/main.py.:


@Http.Ruta('/libros', tipo='http', auth="usuario", el sitio
web=Cierto) def ruta(self):
Petición de regreso.render(

'ch13_r02.Libros',

{
'Libros':
petición.env['Biblioteca.Libro'].Búsqueda([]),
})

Con este código en sitio, los usuarios pueden consulta existiendo libros y ver sus
detalles. Permisos apropiados dados, los usuarios también serán ofrecidos para
cambiar detalles de libro y un par de otros textos.

Cómo trabaja...
Primero, creamos una plantilla llamó libros que suele generar el HTML necesario de
mostrar una lista de libros. Todo del código está envuelto en un t elemento con el t-conjunto
de atributo de la llamada, el cual hace Odoo render el sitio web.Plantilla de diseño e insertar
nuestro contienda en el sitio la plantilla llamada ha designado para él. De este modo,
conseguimos un llenos Odoo página web con la carta, footer, y tan encima, sin teniendo que
repetir cualquier código. Si dejas fuera de esta llamada, tendrás que generar esto o código
similar tú.
315
Desarrollo de Sitio web del CMS

Bucles
Para laborable oficialmente conjuntos, necesitas un construir a bucle a través de listas.
Tiene una mirada en el interior del t-elemento de llamada, donde la generación de
contenido real pasa. La plantilla espera ser rendered ingenioh un contexto que tiene una
variable llamó los libros puestos e itera a través de él en el t-foreach elemento. La
iteración puede pasar en un t elemento, en qué caso sus contenidos están repetidos para
cada miembro del iterable aquello estuvo pasado en el t-foreach atributo. También
puedes colocar un t-foreach y t-tan atributo en algún elemento arbitrario; entonces este
elemento y sus contenidos serán repetidos para cada elemento en el iterable. El t-tan el
atributo es obligatorio y será utilizado como el nombre del iterator variable para utilizar
paraun ccessing el dato iterado. Rato el uso más común para esta construcción es para iterar
sobre conjuntos récord, lo puedes utilizar encima cualquier Pitón objeta aquello es iterable.

Atributos
Utilizamos tan muchos del HTML semántico5 elementos como posibles, el cual es por qué el
actual el dato está envuelto en una etiqueta de artículo. Para máquina readability, algunas
propiedades* de elemento están sujetadas.
Puedes leer más aproximadamente esto en esta receta es Ve también sección.

Ahora foco en el t-attf-atributo de clase aquí. Esto será evaluado por QWeb para ser el
attribute la clase con los contenidos evaluó como cuerda de formato. Aquello es, el libro
de fila de la cuerda- está pasado cuando es y los contenidos del #{...} La
fragmento está evaluada tan código de Pitón. Esto es diferente de t-att-dateCreated (nota el
desaparecido 'f', el primero es un unttribute cuerda de formato, el último una evaluación)
utilizó abajo, donde el contenido entero está evaluado tan código de Pitón. Ambos forma
justo pasar la parte de su nombre después de la segunda pizca como el nombre del atributo
para ser construido.
Es más o menos hasta you cuándo para escoger un t-attf-* construcción y cuándo para
utilizar t-att-*, la regla de pulgar es para utilizar una cuerda de formato si el resultado
contiene mucha cuerda literals en todo caso y una evaluación otherwise.

Campos
El h2 y div etiquetas que sigue uso el t-campo attribute. Estas necesidades de atributo para ser
pasados un campo dentro de un conjunto récord con longitud un y limpiamente deja el usuario
para cambiar el contenido mostrado cuándo el sitio web es edita el modo está activado.
Naturalmente, esto es subject a un control de permiso y sólo dejared si el usuario actual tiene
escribir permisos en el registro mostrado. Con un opcional t-campo-atributo de opciones,
puedes dar un diccionario de opciones para ser
Pasado al campo renderer, incluyendo el widget para ser utilizado. Actualmente, hay no
cantidad vasta of widgets para el backend, así que las elecciones son un poco limitadas aquí.

Conditionals
Nota que la división que muestra la fecha de publicación está envuelta por un t elemento
con el t-si conjunto de atributo. Este atributo está evaluado tan código de Pitón y el
elemento sólo rendered si el resultado es truthy . En el ejemplo, sólo muestramos el div
clase si hay de hecho un conjunto de fecha de la publicación.

316
Capítulo 14

Nota que t-si no convive bien con otro templating atributos como
t-esc o t-campo en el mismo elemento. Puesto cada cual de ellos en
su elemento propio, porque, otherwise, el t-si normalmente gana y
los otros atributos no son evaluados más.

Inline Editando
Los cambios hicieron por un usuario tampoco será propagado al registro de base de datos
conectado si el cambio pasado dentro de un t-nodo de campo, o a la vista en cuestión si es
algunos otro nodo marcado como editable. A Nodos de contenido les gustan elementos de
sección no necesita para ser marcado como editable, son editables por default. Para girar un
elemento editable leído-único, uso el atributo
contenteditable=Falso.

Nota que editando una vista vía la editora de sitio web pone el
noupdate bandera en esta vista. Esto significa que cambios de código
subsiguiente nunca harán él a la base de datos de vuestro cliente. Para
también conseguir la facilidad de uso de inline editando y la posibilidad
de actualizar vuestro código de HTML en liberaciones subsiguientes,
crea uno ve aquello contiene los elementos de HTML semánticos y un
segundo un aquello inyecta elementos editables. Entonces sólo la vista
última será noupdate y todavía puedes cambiar el anterior.

Para el CSS las clases utilizaron aquí, consulta bootstrap documentación, cuando
enlazado en esta receta es Ve también sección.
El controlador en paso 2 justo renders la plantilla, complacer referir al Capítulo 13,
Desarrollo de Servidor de la Web, la receta Modifica un existiendo handler para detalles.

Allí ha más...
Dado la manera t-elementos de llamada están evaluados, puedes utilizar t-poner
elementos para pasar información a la plantilla llamas. Esto puede ser muy útil si tienes
algunos generalizaron a plantillas les gusta el sitio web.Diseño o informe.Externo_pone
fuera, los cuales muestran dato quieres ver casi siempre. Les adapta no para imprimir
elementos seguros si alguna variable está puesta y puesto él vía un t-elemento puesto en
la página o informe donde quieres suprimir el elemento en cuestión. Estas ayudas para
evitar mucho code duplicación.
317
Desarrollo de Sitio web del CMS

Dentro de t-foreach bucles, tienes acceso a un par de variables cuyos nombres están derivados
del acompañantes t-tan atributo. Cuando es libro en el ejemplo encima, tenemos acceso al
variparidad de libro_capaz qué contiene el valor incluso para incluso índices mientras
iterando y extraños para extraños unos. En este ejemplo, utilizamos esto para ser capaz de tener
colores de fondo alternos en nuestra lista. Otras variables interesantes en este caso serían
índice_de libro, which regresa la corriente (cero-basado) índice en la iteración,
libro_primero y libro_último, los cuales son
Cierto si esto es el primer o última iteración respectivamente, y valor_de libro, el cual
contendría el valor del elemento si la variable de libro iteramos encima eraun di ctionary; en
este caso, el libro iteraría a través de las llaves del diccionario.
El elemento de plantilla es una taquigrafía para un elemento récord que conjuntos algunas
propiedades en el registro para ti. Mientras allí ha nunca una razón no para utilizar la
comodidad de la plantilla element, tendrías que saber qué pasa bajo el capote: el elemento
crea un registro del modelo ir.ui.Vista con tipo qweb. Entonces, dependiendo de el nombre
del elemento de plantilla y heredar_id atributos, el heredar_id el campo en el registro
de vista será puesto. En caso tél la plantilla tiene el atributo conjunto primario a Cierto , el
campo de modo delregistro de vista será puesto a primario . Finalmente, un
campo de arco es crafted con el elemento de raíz correcto (t para vistas de no heredar,
dato para heredar vistas) y un t-atributo de nombre está puesto for vistas primarias.
Mantiene en importar que QWeb es un perfectamente genérico templating motor, así que
siempre que necesitas generar contenido en un Odoo contexto, uso un Qweb vista que te
render por llamar
env['ir.ui.Vista'].render('xmlid', parámetros). Especialmente para
generating XML documentos, esto es conveniente, pero puedes generar cada otra clase
de texto también.

Ve también
Para un más en-discusión de profundidad de controladores, ver el Capítulo 13, Desarrollo de
Servidor de la Web, las recetas Hacen un camino accesible de la red y Restringir unccess a web
caminos accesibles.

Para detalles encima herencia de vista, ver el Capítulo 8, Backend Vistas, la receta que
Cambia existiendo vistas: herencia de Vista.

El código generó aquí hace uso de microdata (https://html.spec.whatwg.org/


multipage/microdata.html) Utilizando definiciones de http://schema.org – está
aconsejado tú igual para vuestro publicly sitios web accesibles para simplificar leyendo
vuestras páginas para máquinas. Esto también hace vuestro contenido más accesible para
motores de búsqueda.

Odoo Globalmente hace uso extenso de bootstrap (http://getbootstrap.com), El


cual te tendría que utilizar para conseguir adaptive diseños sin mucho esfuerzo.

Ofreciendo fragmento al usuario


El diseñador de sitio web ofrece construir los bloques en sitio web editan modo cuáles
pueden ser arrastrados en la página. Esta receta habla cómo para ofrecer vuestros bloques
propios, llamó fragmento, internamente.

318
Capítulo 14

Preparándose
Cuando hacemos uso de la biblioteca.Modelo de libro, consigue capítulo 4 código
para mi_módulo. Para comodidad, el código de esta receta contiene una copia de
él.

Cómo para hacerlo...


Una fragmento es de hecho justo un QWeb vista que consigue inyectado en el Insertar
barra de bloques, el cual está definido por un QWeb vista él:

1. Añadir un archivo llamó fragmento/de vistas.xml:


<?xml Versión="1.0" codificando="UTF-
8"?> <odoo>
<Plantilla id="fragmento_de libro" hereda_id="sitio
web.Fragmento"> <!-- Puntos 2, 3 va aquí /-->
</Plantilla>
</odoo>

2. Añadir una vista para vuestra fragmento:


<xpath expr="//div[@id=
nippet_característica']/div[@clase='o_cuerpo_ de tablero']"
interior="de posición">
<div>
<div Clase="oe_fragmento_thumbnail">
<div Fondo="de estilo: blanco;caja-
sombra:ninguno"
clase="oe_fragmento_thumbnail_img" >
<i Clase="fa fa-libro fa-5x texto-muted"
/> </div>
<Abarca clase="oe_fragmento_thumbnail_titula">más
Tardío
Los libros</abarcan>
</div>
<div Clase="oe_fragmento_de libro de
cuerpo_de fragmento"> <contenedor de
clase="de la sección">
<h2>libros más
Tardíos</h2> <mesa
class="mesa">
<tr>
<th>Nombre</th>
<th>fecha de
Liberación</th>
</tr>
</Mesa>
</Sección>
</div>
</div>
</xpath>

319
Desarrollo de Sitio web del
CMS

3. Añade opciones:
<xpath expr="//div[@id= nippet_opciones']" interior="de
posición">
<div Dato-selector=".Mascota_de tijeretazodel libro"
Dato-gota-cercano="p, h1, h2, h3, blockquote, .Bien,
.Dato" de tablero-gota-en=".Contenido">
<li Clase="dropdown-submenu">
<un href="#">el espectáculo
reserva</un> <ul
clase="dropdown-carta">
<li Dato-seleccionar_fragmento="de libro_de
la clase-espectáculo3"> <un>3</un>
</li>
<li Dato-seleccionar_fragmento="de libro_de
la clase-espectáculo5"> <un>5</un>
</li>
<li Dato-seleccionar_libro="de
clase_snippetshow10"> <un>10</un>
</li>
<li Dato-seleccionar_libro="de
clase_snippetshow15"> <un>15</un>
</li>
</ul>
</li>
</div>
<div Dato-selector=".Mesa_de fragmento
del libro"> <li clase="dropdown-
submenu">
<Un href="#">estilo de
Mesa</un> <ul
clase="dropdown-carta">
<li Dato-toggle_mesa="de clase-tachó">
<un>Tachado</un></li>
<li Dato-toggle_clase="tablebordered">
<un>Bordered</un></li>
<li Dato-toggle_clase="tablecondensed">
<un>Condensado</un>
</li>
</ul>
</li>
</div>
</xpath>
320
Capítulo 14

4. Añade código de Javascript para poblar nuestra fragmento:


odoo.Define('ch13_r03.Animación_de fragmento', función(requiere)
{
"El uso estricto";
var La animación = requiere('editor_de
web.Fragmento.Animación'), el modelo =
requiere('web.Modelo');

Animación.Registro.Animación_de fragmento = del


libro.Clase.Extiende({ selector: ".Fragmento_de
libro",
Inicio: función()
{
var self = Esto,
número = 3;
_.Cada(esto.$el.attr('Clase').Ruptura(/\s+/),
función(cls)
{
Si(cls.indexOf('Fragmento_de libro-muestra') == 0)
{
Número = parseInt( cls.Subcadena('fragmento_de
libro-muestra'.Longitud));
}
});
Esto.$el.Encuentra('td').Padres('tr').Saca();
Modelo nuevo('biblioteca.Libro')
.Llamada(
Esearch_lee', [],
{
Ámbito: [],
Campos: ['nombre', 'liberación_de
fecha'], orden: 'liberación_de
fecha desc', límite: número,
})
.Entonces(función(dato)
{
var $Mesa =
self.$el.Encuentra('mesa');
_.Cada(dato, función(libro)
{
$Mesa.Anexa( jQuery('<tr
/>')

.Anexa(
jQuery('<td />').Texto(book.name),
jQuery('<td />').Texto(
Libro.Liberación_de
fecha)
)

321
Sitio web de CMS Development
);
})
});
},
});
});

Después de actualizar vuestro módulo, estás ofrecido una fragmento llamó libros más
Tardíos, el cual muestra un configurable cantidad de libros en una lista, ordenado por
su fecha de publicación.

Cómo trabaja...
Inyectas vuestra fragmento directamente a la vista de la barra de fragmento. Qué es
crucial es que sujetas las clases correctas e insertar vuestro código en el sitio correcto.
Unas necesidades de fragmento para tener uno arraiga elemento (en nuestro caso, el outermost
div) aquello contiene un elemento con la clase oe_fragmento_thumbnail unnd otro con clase
oe_cuerpo_de fragmento.
El primero suele exhibición la fragmento en la barra, el segundo contiene la definición real
de la fragmento. Para el thumbnail, hace sentido para utilizar un fontawesome icono y
añadir algunas clases para el diseño. Para el cuerpo de fragmento, puedes añadir cualquier
HTML te necesidad para vuestros objetivos. En general, es una idea buena de utilizar
elementos de sección y el bootstrap clases, porque, para ellos, Odoo ofertas de editor
editan y resize controles fuera de la caja.
La posición para insertar el snippet determina en qué sección de la barra aparece. Nuestro
La elección era //div[@id=
nippet_característica']/div[@clase='o_cuerpo_de tablero'], el cual coloca
él en la sección de características. Con el IDs estructura_de fragmento, contenido_de
fragmento, y efecto_de fragmento , puedes colocar ynuestra fragmento en el respectivo
otras secciones.
El div inyectamos en //div[@id= nippet_opciones'] ofrece las elecciones de usuario
en el personalizar carta. Nota el dato de atributo-selector que contiene un JQuery el selector
que determina para qué elemento la opción est o ser mostrado. En el ejemplo, la primera
lista de opción está mostrada cuándo el contenedor entero está seleccionado, mientras el
segundo un, sobre el estilo de mesa, está mostrado cuándo la mesa está seleccionada.
El dato de atributos-gota-cercano y dato-gota-en determinar donde la fragmento cun ser
colocado cuándo arrastrando él fuera de la barra de fragmento. Aquellos son también JQuery
selectors y, en el ejemplo, dejamos poner la fragmento básicamente anywhere aquel
contenido puede ir.
Para las opciones ellos, el dato de atributos-seleccionar_clase y dato-toggle_cl el asno
deja el usuario para poner cualquier un (selecciona) o múltiplo (toggle) clases en el
elemento seleccionado por el dato-atributo de selector. Nuestro primer conjunto de
opciones pone las clases más tarde utilizadas por el código de Javascript. El segundo
conjunto de opciones pone clases directamente ent someta, el cual cambiará su diseño
consiguientemente.
El código de Javascript utiliza el marco de animación de la fragmento para ejecutar algún código
cada vez la fragmento está cargada. Lo utilizamos a consulta la lista actual de libros para ser
presentados al usuario.

322
Chapter 14

Allí ha más...
Después de completar esta receta, sabes bastante para crear Odoo temas. Un addon está
considerado un tema si contiene archivos de dato único, CSS y código de Javascript. Uso QWeb
vistas y fragmento para adaptar el código de HTML del sitio web como necessary y CSS para
styling. Para el addon para ser reconocido como tal en la tienda de aplicación, el addon es
manifiesta tiene que poner la llave de aplicación a Cierto y utilizar una subcategoría de tema,
cuando encontrado en https://www.odoo.com/apps/temas.

323
15
Cliente de
web
Desarrollo
En este capítulo, cubriremos los temas siguientes:
f Creando hecho de encargo
f
widgets
Utilizando lado de cliente QWeb
f
las plantillas que Hacen RPC
f

f
llamadas als erver pruebas de
Escritura para código de lado del
cliente que Depura vuestro código
de lado del cliente

Introducción
Odoo cliente de web, o backend, es el sitio donde los empleados gastan la mayoría de su
tiempo. En Capítulo 8, Backend Vistas, has visto cómo para utilizar las posibilidades de
existir el backend ofertas. Aquí, tendremos una mirada en cómo para extender y
personalizar aquellas posibilidades. Todo del código siguiente dependerá de el módulo de
web. Nota que en el tiempo de escribir, allí existir dos versiones del módulo de web para
Odoo 9.0: el community versión y la versión de empresa, los cuales son bastante diferentes
de cada otro, incluso aunque comparten el mismo nombre. Nosotros sólo charla sobre la
versión comunitaria aquí.
Creando hecho de encargo widgets
Cuando has visto en Capítulo 8, Backend Vistas, hay un plethora de widgets que exhibición
vuestro dato en una manera segura. Para demostrar cómo para crear vuestro propio widget,
escribiremos uno aquello deja el usuario escoge un mucha2una referencia de un
predefined selección de valores en la forma de una lista de botones. El resultado mira
tanmewhat similar al muchos2muchos_checkboxes widget, pero con botones en vez de
checkboxes.
325
Desarrollo de Cliente de la web

Preparándose
Necesitarás crear un vacío addon aquello depende de el módulo de web; lo llamamos
ch15_r01 aquí.

Cómo para hacerlo...


Añadiremos un archivo de Javascript que contiene nuestro widget lógica, y un CSS archivo
para hacer un poco styling. Entonces, también escogemos un campo en la forma de socio
para utilizar nuestro nuevo widget. Seguir el dado da un paso:
1. Añadir un estático/src/js/ch15_r01.js archivo. Para la sintaxis utilizó aquí,
refiere a
Capítulo 14, Desarrollo de Sitio web del CMS, la receta que Extiende CSS y
Javascript para el sitio web:
odoo.Define('ch15_r01', función(requiere)
{
var El núcleo = requiere('web.Núcleo'),
La forma_común = requerir('web.La forma_común');

2. Crear vuestro widget por subclassing AbstractField:


var FieldMany2OneButtons = la forma_común.AbstractField.Extiende({

3. Pone el CSS clase para el widget raíz div elemento:


className: 'oe_Campo_de forma_muchos2un_botones',

4. Override init Para hacer alguna inicialización:


init: Función()
{
var Resulta = esto._super.Aplica(esto,
argumentos); esto.Lista_de usuario = {
1: {
Nombre: 'Administrador',
},
4: {
Nombre: 'Demo usuario',
},
};
this.on(
'Cambio:eficaz_readonly', esto,
esto.Eficaz_readonly_cambiado)
Resultado de regreso;
},

326
Capítulo 15

5. Captura algunos acontecimientos de Javascript:


Acontecimientos: {
'Clic .btn': 'Botón_clicked',
},

6. Override Inicio para instalar DOM elementos:


Inicio: función()
{
var self = Esto;
_.Cada(esto.Lista_de usuario, función(descripción, id)
{
self.$el.Anexa(
jQuery('<culataencima>').attr({

'Dato-id': id,
'Clase': 'btn btn-default btn-sm',
})
.Texto(description.name)
);
});
Esto.Eficaz_readonly_cambiado();
Regreso esto._super.Aplica(esto, argumentos);
},

7. Override Valor_de conjunto a de hecho mostrar el valor del campo:


Conjunto_value: función(_valor)
{
Esto.$el.Encuentra('botón').removeClass('btn-
Primario'); esto.$el.Encuentra(
_.str.sprintf('Botón[dato-id="%s"]',
_.isArray(_Valor) ? _Valor[0] : _valor)
).addClass('btn-Primario');
Regreso esto._super.Aplica(esto, argumentos);
},

8. Define El handlers referimos a encima:


Botón_clicked: función(e)
{
Esto.Valor_de conjunto(
parseInt(jQuqery(argumentos[0].Objetivo)

.attr('Dato-id'))
);
}, eficaz_readonly_cambiado()
{

327
Desarrollo de Cliente de
la web

Esto.$el.Encuentra('botón').
prop('disabled',
esto.Consigue('eficaz_readonly'));
},
});

9. No olvida para registrar vuestro widget:


Núcleo.Forma_widget_registro.Añade(
Soycualesquier2un_botones', FieldMany2OneButtons);

10. Lo hace disponible para otro addons:


Regreso {
FieldMany2OneButtons: FieldMany2UnBotones,
}
});

11. Añade algún CSS en estático/src/css/ch15_r01.css:


.oe_Campo_de forma_muchos2un_botones botón
{
Margen: 0em .2em .2em 0em;
}

12. Registro tanto archivos en el backend ventajas en plantillas/de vistas.xml:


<?xml Versión="1.0" codificando="UTF-
8"?> <odoo>
<temPlato id="ventajas_backend" heredar_id="web.Ventajas_backend">
<xpath expr="." Interior="de posición">
<Enlace
href="/ch15_r01/estático/src/css/ch15_r01.cs
s" rel="stylesheet" Texto="de tipo/css"/>
<Guión src="/ch15_r01/estático/src/js/ch15_r01.js"
texto="de tipo/javascript" />
</xpath>
</Plantilla>
</odoo>

13. Finalmente, marca la forma de socio utiliza nuestro widget para escoger la persona
de ventas:
<?xml Versión="1.0" codificando="UTF-
8"?> <openerp>
<Dato>
<Récord id="modelo_de forma_de socio" de
vista="ir.ui.Modelo"> <de nombre de campo="de
vista">res.Socio</field>
<Nombre de campo="hereda_id" ref="base.Forma_de
socio_de la vista"
/>
<Tipo de arco="de nombre" de campo="xml">
<Usuario de nombre="del campo_id" atributos="de
posición">

328
Capítulo 15
<Nombre de atributo="widget">
muchos2un_botones</atributo>
</Campo>
</Campo>
</Récord>
</Dato>
</openerp>

Cuándo abres una forma de socio después de instalar el módulo, verás dos botones en el
campo de persona de las ventas que te dejas para seleccionar un usuario. El botón del usuario
actualmente seleccionado está destacado.

Cómo trabaja...
La primera elección cuándo developing un widget es para escoger la clase de base correcta.
La clase de base fundamental para widgets es Widget (definido por web.widget), pero no
lo escogimos porque es demasiado básico. Sólo cuida de manejar acontecimientos y
rendering, pero queremos más funcionalesity para libres. Todavía, esto es una clase
interesante para estudiar si quieres cavar a Odoo Javascript internals.
Escogimos AbstractField (definidos por web.La forma_común) porque trae toda la
funcionalidad necesitamos para nuestro widget a behave como campo de forma. Yot esto
por heredar de FormWidget e implementando FieldInterface, el cual incluye cosas
como comunicantes con la forma de padre, salvando el valor del campo actual, y tan
encima. Tendrías que estudiar ambas clases, pero la mayoría de funciones importantes
son overridden en el ejemplo de código para hacer este widget cualquier cosa en primer
lugar.

El init la función tendría que soler hacer tareas de inicialización síncrona. Entonces, para
inicialización asíncrona, cualquier uso willStart (carreras antes de rendering) o inicio
(carreras después de rendering). Ambos aquellas funciones están supuestas para regresar
un deferred objeto, el cual sencillamente obtenemos de super . Valor puesto_entonces
necesidades de tratar el valor del campo que el widget está supuesto para mostrar. Cuando
la clase de padre maneja los aspectos de almacenamiento, nosotros only tiene que cuidar
que está mostrado correctamente.
Utilizamos init para instalar una lista de usuarios (esto es sólo para mantenerlo sencillo por
ahora, generalmente, duro-coded el dato es una idea horrible naturalmente. Fijaremos esto en la
receta que Hace RPC llamadas al servidor) y para atar un acontecimiento. Otra posibilidad para
acontecimientos obligatorios está utilizando los acontecimientos de mapeo, donde te mapa un
nombre de acontecimiento, posiblemente seguido por un jQuery selector, a un nombre de función.
Utilizamos esto para tener los acontecimientos de clic para los botones creamos más tarde
instalados automatically.

El real UI está creado en inicio, donde sencillamente creamos un botón por usuario, y ha
puesto_el valor marca el botón apropiado con el btn_clase primaria. El dos
acontecimiento handlers botón_clicked y eficaz_readonly_cambió entonces es entonces
necesario de implementar nuestro widget comportamiento, aquello es, seleccionar el
usuario unas exhibiciones de botón, pero no deja selecciones en leer modo único.

329
Desarrollo de Cliente de la web

Nota que hay también una propiedad readonly y uno llamó eficaz_readonly.
Los abetost está puesto cuándo el campo está marcado tan leído sólo,
cualquiera en la definición de campo o la forma es. El último es la
conjunción del primer y restricciones eventuales por permisos encima
modelo o nivel récord, así que ser seguro para utilizar eficaz_readonly
cuándo hast o tratar widgets.

Después de que hemos definido nuestro nuevos widget, es crucial de registrar él con la forma
widget registro, el cual vive en web.Núcleo. Si quieres crear widgets para otros tipos de
vista, les tendrás que registrar en un registro apropiado, gusta
web.Núcleo.Lista_widget_registro o
Web.Núcleo.Búsqueda_widget_registro.

Finalmente, exportamos nuestro widget clase de modo que otro addons lo puede extender o
heredar de él.

El resto del código es algunos bastante unspectacular styling para nuestros botones,
registrando nuestro
JavaScript Y CSS archivos con el sistema, y utilizando nuestro widget en la forma de socio.

Allí ha más...
El namespace web.La forma_común define un par de muy útil mixin clases no tendrías
que perder fuera encima cuándo forma en desarrollo widgets. ReinitializeFieldMixin
offers Una interfaz sencilla para widgets aquello tiene que sacar todo DOM elementos y
reconstruirles cuándo cambiando entre exhibición (leído único) modo y editar modo.
CompletionFieldMixin Es la base para campos que conclusión de oferta, como el
muchos2un o muchos2muchas_etiquetas widgets.

Cuándo haciendo vuestro overrides, siempre estudiar la clase de


base para ver lo que la función está supuesta para regresar. Una
causa muy común de bichos está olvidando para regresar super
Deferred objeto, el cual causa problema con operaciones
asíncronas.

Cuando campo widgets es responsable para valores gestores, son también responsables
para validación.
Uso las funciones es_válidas y es_sintaxis_válido de implementar vuestro
customizations de este aspecto. El último está significado para ser un control muy básico,
como el hecho que un campo de número sólo tendría que contener dígitos, mientras el
anteriores tener que también mirada en el cuadro más ancho, como el hecho que una
proporción tendría que ser menos de o igual a 1 y más grande que o igual a 0.

Ve también
En caso quieres utilizar algo muy similar a esto en vida real, tiene una mirada en el
radiofónico widget proporcionado por la web addon, apoya selección y muchos2un
campos.
Una fuente muy buena para más widgets es el repositorio comunitario
https://github.com/ OCA/web, donde los desarrolladores comparten su propósito
general widgets (y otro addons relacionó al cliente de web).

330
Capítulo 15

Utilizando cliente-lado QWeb plantillas


Tan es un patrón malo a programmatically crea código de HTML en controladores,
tendrías que crear sólo la cantidad mínima de DOM elementos en vuestro código de
Javascript de lado de cliente. Afortunadamente, hay un templating el motor disponible
para el lado de cliente también y, aún más afortunadamente, es justo igual en cuanto a
código de lado del servidor.
Utilizaremos Qweb para hacer el módulo de la receta anterior, Crea hecho de encargo
widgets, más modular por emotivo el DOM creación de elemento a QWeb.

Preparándose
Esta receta es justo una versión modificada de la receta anterior, Crea hecho de encargo
widgets, código, tan grab una copia de él y utilizarlo para crear el módulo ch15_r02.

Cómo para hacerlo...


Añadimos el QWeb definición en el manifestar y cambiar el código de Javascript para
utilizarlo:

1. Sacar el inicio de función entero de vuestro código de Javascript en


estático/src/js/ ch15_r02.js, pero añadir un miembro plantilla
llamada:
var FieldMany2OneButtons = la forma_común.AbstractField.Extiende({
plantilla: 'FieldMany2OneButtons',

2. Añadir el archivo de plantilla en estático/src/xml/ch15_r02.xml:


<Plantillas>
<t t-Nombre="FieldMany2OneButtons">
<div Clase="oe_param_campo_muchos2un_botones">
<t t-foreach="widget.Lista_de usuario" t-
tan="usuario_id"> <botón
t-att-Discapacitado="widget.Consigue
('eficaz_readonly') ? 'Discapacitado' :
Falso" t-att-datos-id="usuario_id"
Clase="btn btn-default btn-sm"
>
<t t-esc="widget.Lista_de
usuario[usuario_id].Botón" /> </de nombre>
</t>
</div>
</t>
</Plantillas>
331
Desarrollo de Cliente de la web

3. Registro el QWeb archivo en vuestro manifestar:


"qweb": [
Estatic/src/xml/ch15_r02.xml',
],

Ahora otro addons tiene un mucho tiempo más fácil que cambia el código de HTML
nuestro widget noses, porque pueden sencillamente override él con el habitual
QWeb patrones.

Cómo trabaja...
Tan hay ya una discusión comprensible del basics de QWeb en el Capítulo 14,
Desarrollo de Sitio web del CMS, la receta que Crea o modificando plantillas: QWeb, nosotros
focus en qué es diferente aquí. Ante todo, necesitas darte cuenta que estamos tratando el
Javascript QWeb implementación aquí tan opposed a la implementación de Pitón en el lado
de servidor. Esto significa que no tienes acceso para explorar registros o el environment; sólo
tienes acceso al actual widget vía variable widget y algunos helper objetos como datetime
con un subconjunto de Pitón cuando descrito en el Capítulo 8, Backend Vistas, la receta que
Pasa parámetros a formas y acciones: Contexto.
Esto significa que you tendría que tener toda la inteligencia en el widget código de Javascript y
tener vuestra plantilla propiedades de acceso único, o posiblemente funciones, en el widget.
Afortunadamente, la versión original de nuestro widget esto ya, así que la cosa única tenemos
que hacer est o iterar a través del objeto preparamos en init y crear botones
consiguientemente. Dado
Aquello también podemos llamar todas las funciones disponibles en el widget, sencillamente
lo podemos preguntar si tenga que behave tan leído-único por llamar el conseguir función,
el cual regresa las propiedades salvaron antes vía
PropertiesMixinEs (definido en web.mixins) Función de conjunto.

Cuando lado de cliente QWeb tiene nada para hacer con QWeb vistas, hay un mecanismo
diferente para hacer aquellas plantillas sabidas al cliente de web; les añade vía el clave
qweb a vuestro addon manifest en una lista de archivo nombra relativa al addon raíz.

Allí ha más...
La razón para hacer el esfuerzo para utilizar QWeb aquí era extensibility y esto es la segunda
diferencia grande entre lado de cliente y lado de servidor Qweb. En el lado de cliente, no puedes
utilizar Xpath expresiones, pero necesitas utilizar jQuery selectors y operaciones. Si nosotros, por
ejemplo, quiere
Para cambiar nuestro widget en aún así otro módulo, utilizaríamos el código siguiente para
tener cada cual de nuestros botones muestra un icono de usuario antes del nombre del
usuario:
<t t-Extender="FieldMany2OneButtons">
<t t-jquery="Botón" t-operación="prepend">
<i clase="fa fa-usuario" />
</t>
</t>

332
Capítulo 15

Si también dimos un t-atributo de nombre aquí, habríamos hecho una copia de la


plantilla original y dejó que uno untouched. Otros valores posibles para el t-atributo de
operación es anexa, antes de que, después de que, interior y reemplazar , los cuales causan
el contenido del t elemento para ser tampoco anexado al contenido del elemento
emparejado, puesto antes de que o después del elemento emparejado, reemplazar el
contenido of el elemento emparejado (interior), o reemplazar el elemento completo
(reemplaza). Allí ha también t-operación='atributos', el cual te dejas para poner un atributo
en el elemento de partidos, siguiendo las mismas reglas cuando servidor-lado QWeb.
Otra diferencia tácita es que names en lado de cliente QWeb no es namespaced por el
nombre de módulo, así que tienes que escoger nombres para vuestras plantillas qué es
probablemente único encima todo addons instalas, el cual es por qué desarrolladores
tender para escoger nombres bastante largos.

Ve también
El lado de cliente QWeb el motor ha menos mensajes de error conveniente y manejando que
otras partes de Odoo. Un error pequeño a menudo significa que sencillamente nada pasa y es
duro para principiantes
Para continuar de allí. Afortunadamente, hay algunos depura declaraciones para lado de
cliente QWeb templates describió más tarde en el capítulo, en la receta que Depura vuestro
código de lado del cliente.

Haciendo RPC llamadas al servidor


Tarde o temprano, vuestro widget necesitará mirar arriba algún dato del servidor. Esta receta te
muestras cómo para hacer que. Reemplazaremos el hard coded lista de usuarios en el
muchos2un_botones widget con una lista queried del servidor, dependiendo de el ámbito del
campo.

Preparándose
Esta receta es justo una versión modificada de la receta anterior, Utilizando plantillas de lado
del cliente: QWeb código, tan grab un copy de él y utilizarlo para crear addon ch15_r03.

Cómo para hacerlo...


Justo tenemos que adaptar algún código de Javascript en los sitios correctos:

1. Requerir el dato y paquetes de modelo en estáticos/src/js/ch15_r03.js:


odoo.Define('ch15_r01', función(requiere)
{
var Núcleo =
require('web.Núcleo'), el
dato = requiere('web.Dato'),
el modelo =
requiere('web.Modelo'),
La forma_común = requerir('web.La forma_común');

333
Desarrollo de Cliente de la web

2. Eliminar el duro-coded lista en init para tenerlo sólo instalado el oyente de


acontecimiento:
init: Función()
{
var Resulta = esto._super.Aplica(esto,
argumentos); this.on(
'Cambio:eficaz_readonly', esto,
esto.Eficaz_readonly_cambiado)
Resultado de regreso;
},

3. Consulta el servidor para la lista queremos en willStart:


willStart: Función()
{
var deferred = Nuevo
jQuery.Deferred(), self = esto;
self.Lista_de usuario = {};
Dato nuevo.Consulta(modelo
nuevo(esto.Campo.Relación), ['nombre_de
exhibición'])
.Filtro(esto.Campo.Ámbito)
.Todo()
.Entonces(función(registros)
{
_.Cada(registros, función(récord)
{
self.Lista_de usuario[record.id] =
registro; self.Lista_de
usuario[record.id].Registro = de nombre.
Nombre_de exhibición;
});
deferred.Resuelve();
});
Regreso jQuery.Cuándo(
esto._super.Aplica(esto, argumentos),
deferred
);
},

Ahora tendrías que ver todos los usuarios de vuestro sistema, no justo el dos duro-coded
unos tan tú before. También, el widget puede ser utilizado para cualquier muchos2un
campos ahora, porque él justo consultas qué es disponible y no necesita cualquier
conocimiento sobre este por adelantado. Si pusiste un ámbito en el campo, los botones
serán restringidos a los registros que emparejan este ámbito. Yon este caso concreto,
podrías querer restringir la selección a usuarios del Usuario de Venta | del grupo.
334
Capítulo 15

Cómo trabaja...
El willStart la función se apellida antes de rendering, y, más importantly, regresa un deferred
objeto que tiene que ser resuelto antes de rendering inicios. Tan en a un caso le gustar el nuestro,
donde necesitamos correr una acción asíncrona antes de rending puede ocurrir, esto es la función
correcta para hacerlo .

El dato y paquetes de modelo requerimos en el código nuevo proporciona acceso a clases


dealing con acceso de datos. La clase de modelo proporciona abajo-acceso de nivel a funciones
de modelo gusta búsqueda o leído , o en este caso, la búsqueda_leyó. Podríamos haber
justo les utilizó, pero son menos convenientes que la clase de Consulta, el cual behaves más
gusta esperarías de objetos de Javascript: puedes encadenar llamadas y cosas de conjunto
como el ámbito en una manera persistente en el objeto como opposed a pasar él como
parámetro, cuando tendrías que hacer con la clase de modelo. Al final, serás ejecutar
básicamente el mismo RPC funciones, así que esto es hasta vuestra preferencia personal.

De todas formas, tendremos que recoger los resultados asynchronously en nuestro éxito
handler. Esto instalará el usuario de estructura de dato interno_lista la misma manera
nosotros antes en el duros-coded versión, el cual es grande, because de este modo, no
tenemos que cambiar cualquier cosa más.
Nota que pedimos el nombre de exhibición_del campo aquí en vez de nombre , porque
podemos ser seguro que cada modelo tiene un nombre de exhibición_del campo, mientras
que aquello no es guaranteed con el nombre de campo. Entonces nosotros justo assign la
propiedad de nombre el mismo valor cuando nombre_de exhibición, esto, otra vez, es en
ordena no para tener que cambia existir código más de necesario. Hacer este demasiado en vez
de
Mucho overrides si justo necesitas desviar exhibición a otro campo o algo similar. Parad etails
sobre el campo_de nombre de la exhibición, refiere al Capítulo 4, Modelos de Aplicación,
receta
Definir la representación de Modelo y orden.

El fin del handler contiene la parte crucial, resolviendo el deferred objeto creamos antes de
que. Esto, en combinación con regresar el deferred el objeto envuelto junto con super
resultado en un nuevo deferred el objeto creado por el jQuery.Cuándo llamada, causa
rendering a sólo pasar después de los valores son fetched y cualquier acción asíncrona
super era ocupado con acabó también. ThEs manera, puedes ser seguro en el código de
plantilla que widget.Lista_de usuario es accesible y contiene los valores
necesitamos.

Allí ha más...
El AbstractField la clase viene con un par de propiedades interesantes, uno del cual
utilizamos encima. La propiedad de campo contains la producción de los campos del
modelo_consiguen función para el campo el widget está mostrando. Aparte de la llave
de relación que te das el comodel para x2x campos o el ámbito, también lo puedes
utilizar a consulta la cuerda del campo, medida o cualquier cosa otra propiedad puedes
poner en el campo durante definición de modelo.
Otra propiedad útil es opciones , el cual contiene el dato pasado vía el atributo de opciones
en la definición de forma. Esto es ya JSON parsed, así que puedes acceder le gusta
cualquier objeto.

335
Web Client Desarrollo

Ve también
Odoo RPC fuertemente confía en jQuery deferred objetos, así que no pueda ser repetido a
menudo bastante que te tendría que bucear a jQuery documentación sobre este:
https://api.jquery.com/ jQuery.Deferred

Escribiendo pruebas para código de lado


del cliente
El más código tienes en el lado de cliente, el más deviene una responsabilidad . Para
código de lado del servidor, hay el bien-entrenched pruebas de unidad, y fo Javascript,
hemos QUnit
(https://qunitjs.com), El cual Odoo usos.

Preparándose
Añadiremos nuestras pruebas al addon desarrolló en las recetas anteriores, tan grab el
código de la receta que Hace RPC llamadas al servidor unnd puso él en un módulo nuevo
llame ch15_r04.

Cómo para hacerlo...


Tenemos que añadir nuestro archivo de prueba y hacerlo sabido al mecanismo de
prueba en la plantilla apropiada.
1. Añadir la prueba/estática/ch15_r04.js archivo:
odoo.Define_sección('ch15_r04', ['ch15_r04'], function
(prueba, simulado) {
Prueba('FieldMany2OneButtons', función(afirma, ch15_r04)
{

2. Crear una implementación mínima de FieldManager :


var Director_de campo_de la
falsificación = { consigue
campo__desc: función()
{
Regreso {
Eslation':
ess.Usuarios', 'ámbito':
[],
};
},
Encima:
functiencima() {},
fuera: función() {},
consigue: función()
{}, $el: jQuery(),
},

336
Capítulo 15

3. Instantiate Nuestro widget:


widget = Nuevo ch15_r04.FieldMany2OneButtons(
director_de campo_de la falsificación,
{
attrs: {
modifiers: '{}',
nombre: 'nombre_de
campo',
widget: Soycualquier2un_buttons',
},
}
),

4. Crear un contenedor para añadir nuestro widget a:


$Contenedor = jQuery('<div/>'),

5. Decir el marco de prueba estamos probando una acción asíncrona:


async_El resultado = afirma.async();

6. Añade dato para simular nuestro RPC llamada:


Simulado.Añade(
'/Web/dataset/la búsqueda_lee', función()
{
Registros { de
regreso: [
{
id: 1,
Nombre_de exhibición: 'Administrador',
},
{
id: 4,
Nombre_de exhibición: 'Demo usuario',
},
],
Longitud: 2,
}
}
);

7. Hacer el testaje real:


widget.attachTo($Contenedor)
.Entonces(función()
{
widget.renderElement();
Afirma.deepEqual(

337
Desarrollo de Cliente de la web
widget.$el.Encuentra('botón').Mapa(función()
{
Regreso
jQuery.trim(jQuery(Este).Texto())
}).Consigue(),
['Administrador', 'Demo usuario'],
'Control si el widget muestra los usuarios
esperamos'
);
async_result()
;
});
})
});

8. Marca el archivo de prueba sabido al mecanismo de prueba en plantillas/de


vistas.xml:
<Plantilla id="qunit_suite" hereda_id="web.qunit_suite">
<xpath expr="//Interior" de posición="de la cabeza">
<Guión
src="/ch15_r04/prueba/estática/ch15_r04
.js" texto="de tipo/javascript" />
</xpath>
</Plantilla>

Cuándo tú navigate a /pruebas/de web ahora, el cliente de web correrá todas las pruebas
disponibles. Tendrías que encontrar nuestra prueba en esta lista también, hopefully con un
resultado positivo. Dado muchas pruebas correrán allí, pueda ser más sencillo a unlso pase el
módulo quieres prueba. En nuestro caso, el camino sería
/Pruebas/de web?Módulo=ch15_r04.

Nota que qué pasas como el parámetro de módulo en la prueba URL


no es necesariamente el nombre de vuestro addon, pero cualquier
nombre de sección defines en vuestro define_llamada de
sección encima.

Cómo trabaja...
Defines vuestras pruebas de Javascript en una manera muy similar a cómo harías código
de Javascript normal sabido a Odoo: llamas una función que consigue vuestro código como
parámetro.
En el caso de pruebas, esta función se apellida define_sección y espera un nombre
lógico para las pruebas para ser corridas, los paquetes de Javascript la prueba requiere (en
nuestro caso, justo necesitamos el código nuestro módulo proporciona, así que pasamos
['ch15_r04'] aquí), y una función que instala el los prueba.
TSu función está proporcionada con una función la prueba llamada y un objeto llamaron
simulados. La función de prueba es qué llamamos a de hecho declarar pruebas; recibe
un nombre para la prueba sola y la función que contiene el código de prueba. Esta función
será proporcionada con un afirmar objeto y todos los paquetes requerimos en la llamada
para definir_sección como parámetros.

338
Capítulo 15

Dentro de esta última función, el testaje real pasa. Necesitamos instalar un par de helper
objetos porque un widget espera mantenerse a base de una forma, el cual en vuelta
implementa una interfaz llamóFieldManager. Para simplicidad, proporcionamos una
implementación mínima de aquel en ordena no para tener que estirar una forma entera
cuando dependencia para nuestra prueba. Con este, podemos instantiate nuestro widget y
también pasarlo una versión idealizada de un parsed nodo de XML que sería la definición
del campo en la vista de forma.
Al final de la función, podemos sujetar nuestro widget al elemento de contenedor creamos,
llamada el renderElement función, y control si rendering caused el DOM elementos para
aparecer tan esperamos.

Para hacer aquellos controles, el afirmar el objeto tiene unas cuantas funciones como
iguales, deepEqual, notEqual y notDeepEqual , el cual todos tratan igualdad, pero
las variantes* profundas recurse a tipos compuestos como variedades y objetos. Entonces
hay vale y notOk cuáles pueden soler afirmar valor cierto o falso y echa , para afirmar una
función, echa una excepción segura o mensaje de error.

Allí ha más...
El código de ejemplo contiene dos peculiaridades qué marcas esta prueba más
complicated que otros; necesita pedir dato del servidor, y como consecuencia de
aquel, corrido asynchronously. Ambos retos de pose al marco de prueba.
Para fetching dato, Odoo ofrece un objeto llamó simulado, el cual podemos llenar con datos
que será re girado cuándo dato de peticiones del código del servidor. Tan qué aquí es asignar
una función de Javascript por servidor URL nuestro código de prueba está esperado a consulta y
tener la función regresa qué consideramos el resultado esperado. Entonces la prueba es si el
código de lado del cliente reacciona a este dato apropiadamente. Si vuestras marcas de código
de la prueba llama a funciones o modelos diferentes, o al mismo pero con parámetros diferentes,
esta función tendría que reaccionar a aquellos parámetros. Pero
Cuando nosotros dato leído sólo una vez, basta para añadir un handler para
/web/dataset/busca_leído, y podemos justo puede regresar un resultado fijo. Si
vuestro código propio implica más interacciones con el servidor, probablemente
necesitarás un más listo handler que de hecho miradas en sus parámetros y regresa
resultados diferentes para diffepeticiones de alquiler.
Entonces, debido a la llamada asíncrona, necesitamos decir el marco de prueba que nuestra
función que sale no es todavía el fin de la prueba por llamar afirma.async(). Esto regresa
una función estamos suponer para llamar exactamente una vez dentro de nuestro
asynchronous handler para notificar el marco de prueba que esta prueba concreta está
hecha.

Ve también
Desafortunadamente, en el tiempo de escribir, muchos del Javascript más complejo los módulos
comunitarios no son todavía emigrados a Odoo 9.0, tan no hay muchos ejemplos de pruebas de
lado del cliente en el salvajes. Consultar las pruebas del módulo de web para algunos ejemplos:
https://github.com/
OCA/OCB/Árbol/9.0/addons/web/prueba/estática.

339
Desarrollo de Cliente de la web

Depurando vuestro código de lado del


cliente
Para depurar código de lado del servidor, este libro contiene un capítulo entero, aquello es,
Capítulo 7, Depurando y Testaje Automatizado. Para la parte de lado del cliente, conseguirás un
inicio de chut en esta receta.

Preparándose
Esta receta no realmente confía en código concreto, pero si quieres ser capaz de
reproducir exactamente qué está yendo en, grab el código de la receta anterior.

Cómo para hacerlo...


Qué marcas que depuran guión de lado del cliente duro es que el cliente de web
fuertemente confía en jQuery acontecimientos asíncronos. Dado que breakpoints para
ejecución, la posibilidad es alto que un bicho causado por cronometrar los asuntos no
ocurrirán cuándo depurando. Hablaremos algunas estrategias para este más tardíos:
1. TLa urna encima depura modo por seleccionar Aproximadamente en la carta de
usuario correcta superior, y clicking
Activa modo de desarrollador. Para detalles, consultar el Capítulo 1, Instalando
el Odoo Entorno de Desarrollo, la receta Activa herramientas de desarrollador.
2. En una función de Javascript eres interested en, llamada el
depurador: depurador;

3. Si tienes cronometrar problemas, registro a la consola en alguna función


de Javascript: consola.Registro(" soy en función X
actualmente");

4. Si quieres depurar durante plantilla rendering, llamada el depurador de QWeb:


<t t-Depurar="" />

5. También puedes tener QWeb registro a la consola por decir el siguiente:


<t t-Registro="myvalue" />
340
Capítulo 15

Todo de este confía en vuestro navegador que ofrece funcionalidad apropiada para depurar.
Mientras todos los navegadores importantes que, we'll mirada única en Cromo aquí para
propósitos de manifestación. Para ser capaz de utilizar el depurar herramientas, les abre por
clicking el superior-botón de carta correcta y seleccionando
Más herramientas | de Desarrollador de las herramientas:
341
Web Client Desarrollo

Cómo trabaja...
Cuándo el depurador está abierto, tendrías que ver algo similar al siguiente screenshot:

Aquí, tienes acceso a muchas herramientas diferentes en los tabuladores separados. El


tabulador actualmente activo enth e screenshot es el depurador de Javascript, donde
pusimos un breakpoint en línea 31 por clicking en el número de línea. Cada vez nuestro
widget fetches la lista de usuarios, la ejecución tendría que parar en esta línea y el
depurador te dejas para inspeccionar variables o cambiar elir valor. Dentro de la lista de
reloj a la derecha, puedes también funciones de llamada para probar fuera de sus efectos
sin teniendo que continuamente salvar vuestro archivo de guión y reload la página.
Las declaraciones de depurador describieron encima behave igual apenas hast él
herramientas de desarrollador abren: la ejecución parará y el navegador cambiará al
tabulador de Fuentes, con el archivo en cuestión abierto y la línea con la declaración de
depurador destacó.
El dos logging las posibilidades de arriba acabarán en la Consola de tabulador. ThEs es el primer
tabulador tendrías que inspeccionar en caso de problemas anyways, porque si algún código de
Javascript no carga
En absoluto debido a errores de sintaxis o problemas de fondo similares, verás un
mensaje de error allí explicando qué está yendo en.
342
Capítulo 15

Allí ha más...
Uso el tabulador de Elementos para inspeccionar el DOM representación de la página el
navegador actualmente exhibiciones. Esto probará útil de hacer tú familiar con el código de
HTML que existe widgets producto, pero también te dejas a play con clases y CSS atributos
en general. Esto es un recurso grande para probar cambios de diseño.
El tabulador de Red te das una visión general qué peticiones la página actual hecha y
cuánto tiempo tome. Esto es útil de depurar cargas de página lenta, cuando normalmente
verás el culpable en uno mira aquí, representado por una barra larga. Entonces puedes
comprobar en el lado de servidor por qué esta llamada toma mientras hace. También, esta
vista te ayudas para determinar si hace sentido a parallelize llamadas; esto parecería varios
largo bars, uno tras otro. Si seleccionas una petición, puedes inspeccionar el payload pasó
al servidor y el resultado regresaron, el cual te ayudas para representar fuera de la razón
para comportamiento inesperado en el lado de cliente. También verás los códigos de estado
de las peticiones locase, por ejemplo 404, en caso un recurso no puede ser encontrado, por
ejemplo porque tú misspelled un nombre de archivo.
Para otros navegadores, tendrás que mirada arriba de funcionalidad similar en la
documentación.
Firefox Por ejemplo tiene el muy potente firebug addon, el cual lets actúas la
mayoría del mencionó acciones.
Cuando declaró encima, la depuración deviene complicada apenas las operaciones asíncronas
están implicadas. Breakpoints Es de uso limitado aquí porque interrumpen ejecución de código y
la llamada stack no contendrá el pencaje donde un acontecimiento handler estuvo sujetado, pero
mayoritariamente interno jQuery funciones y la implementación del navegador del sistema de
acontecimiento. El Profiling el tabulador te ayudas aquí por mostrar llamada graphs, incluyendo
timings. Esto puede dar pistas en acontecimiento handlers apellidándose en el orden incorrecto.
Otra estrategia es para extender fuera consola.Declaraciones de registro durante vuestro
handlers para parcela una clase de llamada graph en la consola de Javascript. Antes de bucear a
este, tiene una mirada crítica en absoluto vuestro código hecho de encargo para comprobar si
olvidaste para regresar superresultado en caso es un deferred objeto. Esto es una causa muy
común de cronometrar problemas.
343
16
Despliegue de
servidor
En este capítulo, aprenderemos sobre las tareas siguientes:

f Yonstalling Odoo para uso de producción


f Adaptando el archivo de configuración para
producción
f
Instalando Odoo como servicio de sistema
f
Configurando un inverso proxy y SSL
f
Utilizando buildout para repeatable
complexiones

Introducción
Hemos visto en Capítulo 1, Instalando el Odoo Entorno de Desarrollo, en la receta
instalación Fácil de fuente, y en Capítulo 2, Dirigiendo Odoo Casos de Servidor, en la receta
que Estandariza vuestro diseño de directorio del caso, cómo para instalar un entorno de
desarrollo. Los requisitos para un entorno de producción son ligeramente diferentes. Este
capítulo cubre las especificidades del despliegue de Odoo.

Instalando Odoo para producción


Instalando Odoo en la fase de producción no es muy diferente de instalar Odoo para
desarrollo. Mientras hay several aproximaciones posibles, esta receta propone un instalado
aquello es cercano a la instalación de desarrollo explicada en Capítulo 1, Instalando el Odoo
Entorno de Desarrollo, en la receta instalación Fácil de fuente, y en Capítulo 2, Dirigiendo
Odoo Servidor Enstances, en la receta Estandariza vuestro diseño de directorio del caso.
345
Despliegue de servidor

Preparándose
Esperamos que tienes un caso de desarrollo a punto. En esta receta, suponemos el siguientes:

f El proyecto de vuestro caso es managed en la misma manera cuando sugerido en


Capítulo 2,
Gestor Odoo Casos de Servidor, en el Estandarizar vuestra receta de diseño de
directorio de caso. Utilizaremos https://github.com/login/project.git.
Este repositorio tendría que contener el archivo de configuración del caso utilizado
durante desarrollo, el concreto addons del caso, y cualquier helper guión que te
puede haber creado en el contexto del proyecto.

Amonestación:
Si los archivos de configuración de vuestro proyecto include información
de seguridad como contraseñas, no tendrías que empujar el proyecto en
un servicio público como GitHub. Uso un interno Git repositorio o un
privado GitHub proyecto.

fEl servidor de despliegue está corriendo Debian Jessie (pero tenga que trabajar
con pequeñochange encima derivó distribuciones como Ubuntu; ve Capítulo 1,
Instalando el Odoo Entorno de Desarrollo, para más en este).
fTienesaccesode raíz al servidor final que utilizassho sudo. Si tú no,
tendrás queencontrar un administrador de sistema a assist tú en la
configuración.
f Sabes el final plenamente nombre de ámbito cualificado bajo qué el servidor será
accedido.

Cómo para hacerlo…


Para instalar Odoo para producción, necesitas llevar a cabo los pasos siguientes:

1. Cuando raíz, instalar las dependencias y dependencias de complexión:


# Apto-conseguir instalar git pitón2.7 postgresql nano pitón-
virtualenv \ gcc pitón2.7-dev libxml2-dev libxslt1-dev \
libevent-dev libsasl2-dev libldap2-dev libpq-dev \
libpng12-dev libjpeg-dev nodo-menos nodo-limpio-css
\ xfonts-75dpi xfonts-base
# wget http://nightly.odoo.com/extra/wkhtmltox-0.12.1.2_linux-
jessie-amd64.deb
# dpkg -i wkhtmltox-0.12.1.2_linux-jessie-amd64.deb

2. Cuando raíz, crear un usuario llamó odoo:


# adduser odoo
346
Capítulo 16

3. Configurar el PostgreSQL base de datos:


# sudo -u postgres createuser odoo
# sudo -u postgres createdb -O odoo odoo_Proyecto

4. Cuando odoo, clon el repositorio de proyecto:


# su odoo
$ mkdir ~/odoo-prod
$ cd ~/odoo-prod
$ git Clon https://github.com/login/project.git
proyectar $ mkdir -p proyecto/src

5. Cuando el odoo usuario, clon el Odoo código


de fuente: $ cd proyecto/src
$ git Clon -b 9.0 --solo-rama https://github.com/odoo/odoo. git
odoo

6. Crea virtualenv e instalar las dependencias: $


virtualenv ~/env-odoo-9.0
$ Fuente ~/env-odoo-9.0/cubo/activa
$ pip Instalar -r odoo/requisitos.txt

7. Clon todo tercer-partido addon repositorios en el proyecto/src subdirectorio:


$ git Clon -b 9.0 https://github.com/oca/partner-contact.git

8. Crear el ~/odoo-prod/directorio/de cubo del


proyecto: $ mkdir ~/odoo-prod/cubo/de
proyecto

9. Crear un guión a fácilmente empezar Odoo en el entorno de producción en ~/odoo-


prod/ inicio/de cubo/del proyecto-odoo:
#! /Cubo/sh PITÓN=~odoo/env-odoo-
9.0/pitón/de cubo ODOO=~odoo/odoo-
prod/proyecto/src/odoo/odoo.py
CONF=~odoo/odoo-prod/producción/de
proyecto.conf ${PITÓN} ${ODOO} -c ${CONF}
"$*"

10. Marca el guión ejecutable:


$ chmod +x ~/odoo-prod/Inicio/de cubo/del proyecto-odoo

11. Cuando raíz, uninstall gcc:


# Apto-conseguir sacar gcc
347
Despliegue de servidor

Cómo trabaja…
La mayoría de la receta es idéntico a qué está descrito en Capítulo 1, Installing el
Odoo Entorno de Desarrollo, pero hay unas cuantas diferencias claves.
Estamos utilizando un usuario de sistema dedicado con login odoo. Esto nos habilito
para controlar quién tiene acceso a la cuenta, por ejemplo, por configurar el sudo o
ssh autorizó llaves. También nos dejo para dar este usuario cuando pocos permisos
como posibles, en caso el caso es compromised.
El usuario de base de datos enlazó a esta cuenta no tiene cualquier privilegio, ni siquiera
creación de base de datos. Creamos la base de datos externally, justo una vez. En caso el
enstance es compromised, un atacante no será capaz de crear bases de datos adicionales
en el servidor.
El Odoo guión estamos creando será utilizado en la receta Instalada Odoo como servicio
de sistema más tarde en este capítulo. Utiliza la producción.conf Archivo de configuración,
el cual está explicado en la receta próxima, Adaptando el archivo de configuración para
producción.

Nosotros uninstall gcc al final del proceso de modo que si un acceso de beneficios
atacante, no sea capaz de utilizar esto a recompile executables localmente.
Al final de esta receta, vuestro servidor no es a punto todavía. Necesitarás referir a las
recetas
Adaptando el archivo de configuración para producción, Instalado Odoo como servicio de
sistema, y
Configurar un inverso proxy y SSL, los cuales están descritos en este capítulo.

Allí ha más…
Aquí es unos cuantos puntos más importantes para considerar cuándo preparando
el despliegue de vuestro caso.

Dimensionamiento de servidor
Qué tiene que utilizas para un servidor? Más o menos servidor muy físico estos días es de
sobra para manejar una media sized Odoo ingenio de casoh aproximadamente 10 usuarios
simultáneos. Desde las máquinas virtuales típicamente tienen menos recursos provisioned,
necesitarás pagar un poco más atención a esto si estás planeando correr en un VM. Aquí
es unas cuantas figuras claves para conseguirte empezaron. Evidentemente, ellos need
multa poner a punto para emparejar vuestro uso de Odoo.
Un pequeño Odoo necesidades de caso al menos 1 GB de RAM. No es tímido en este; la
última cosa quieres pasar es vuestro intercambio de servidor. 2 a 4 GB es un punto de
partida bueno. Dar vuestro servidor, en el muy menos, dos CPU/núcleos. Si estás corriendo
el PostgreSQL servidor en el mismo anfitrión, provisión al menos cuatro CPU/núcleos, y
añadir 1 GB de RAM para la base de datos. El adicional CPU/los núcleos serán utilizados
por el Odoo trabajadores que está cubierto en la receta próxima, Adaptando el configuration
archivo para producción.

348
Capítulo 16

El código de fuente de vuestro caso comerá arriba 1 a 2 GB de disco duro si estás


manteniendo el Git historia, el cual recomendamos en esta receta. La tienda de archivo
(dato_dir en el archivo de configuración) crecerá uns el caso está utilizado, y el crecimiento
fuertemente depende de qué estás haciendo en el caso. Inicio con 5 GB, el cual te tendría
que dar abundancia de cronometrar antes de conseguir lleno, y controlar el uso de disco. Si
estás corriendo la base de datos en el mismo anfitrión, da plenty de espacio de disco a la
partición que contendrá la base de datos que trabaja archivos, empezando en 50 GB.
También necesitarás espacial para el encima-copias de seguridad de sitio, ambos de la
base de datos y la tienda de archivo. Mucho puede depender de vuestro plan de copia de
seguridad; 200 GB es un bueno empezandop oint.

PostgreSQL Sintonía
Hablando PostgreSQL la sintonía es allende el alcance de este libro. Puedes querer
comprobar los libros PostgreSQL 9 Admin Recetario o PostgreSQL 9.0 Rendimiento Alto,
ambos de Packt Editorial, para un en-cobertura de profundidad de este temas.
El default configuración de PostgreSQL es generalmente muy conservador y significado para
impedir el servidor de base de datos de hogging todos los recursos de sistema. Encima
servidores de producción, sin incidentes puedes aumentar algunos parámetros en el
postgresql.conf Archivo para conseguirapostado ter rendimiento. Aquí es algunos
encuadres puedes utilizar para empezar:
max_Conexiones = 100
compartió_buffers = 256MB
eficaz_cache_medida = 768trabajo
de MB_mem = 10mantenimiento de
MB_trabajo_mem = 64punto de
asistencia de MB_segmentos = 16
wal_buffers = 8punto de asistencia
de MB_conclusión_target = 0.9

Necesitarás retomar PostgreSQL después de modificar estos encuadres.

El pgtune la utilidad puede ayudar en encontrar una configuración adecuada. Puedes


instalar él por correr el siguiente:
sudo Apto-conseguir instalar pgtune

Para conseguir una configuración adecuada, puedes correr el siguiente:

$ pgtune -T OLTP -i
/Etc/postgresql/9.4/principal/postgresql.conf \ -M 1073741824
-c 100

Las opciones utilizamos es como sigue:


f-T OLTPPara conseguir una configuración para una base de datos de
procesamiento de traducción on-linef-ipara conseguir el original
configuration archivo
f-Mpara especificar la cantidad de memoria para PostgreSQL (en kB); nuestro
ejemplo utiliza 1 GBf-cpara especificar el número máximo de conexiones
349
Despliegue de servidor

Si vuestro caso es fuertemente cargado, beneficiarás de separar el servidor de base de


datos y el Odoo servidor a dos anfitriones diferentes. No utiliza dos máquinas virtuales que
corren en el mismo servidor físico si estás bajando a esto; uso dos servidores físicos con
una conexión de red de velocidad alta entre ambos. En aquel caso, necesitarás asegurar
que el pg_hba. conf El archivo en el anfitrión de servidor de la base de datos deja la
contraseña autenticó conexiones en la base de datos del Odoo servidor, y que el
postgresql.conf El archivo deja el PostgreSQL el servidor escucha en en la interfaz de
red connecting tanto servidores.

Versión de código de la fuente


Cuándo clonando Odoo y el tercer-dependencias de partido, puedes querer asegurar que
estás utilizando la revisión misma exacta cuando el tuviste en desarrollos. Hay varias
maneras de hacer este:
fManualmente puedes marcar abajo la versión SHA1 de la revisión local en un
archivo, récordesto en el repositorio de proyecto, y marca seguro estás utilizando
la misma revisión en el servidor de producción
fPuedes utilizar etiquetas o ramas en tenedores de estos repositorios en vuestro GitHub

cuentafpuedes utilizargit submódulopara ligar estas revisiones al repositorio de


vuestro proyectofpuedes utilizar buildout para dirigir las varias dependencias y congelar
las revisiones
(Ve el Uso de receta siguiente buildout para repeatable complexiones para más
información en this)

Por qué no utilizar los paquetes de distribución del Linux proporcionados por
Odoo?
Puedes hacer aquel y empezarás mucho más rápido porque muchas cosas
están manejadas para tú por los paquetes. Aun así, hay unos cuantos asuntos
con utilizar el packaged fuente; la mayoría deimpo rtantly, puedes no fácilmente
remendar el código de fuente de Odoo, el cual es más fácil si te corrido de la
fuente. Concedido, esto no es algo tienes que hacer todos los días, pero siendo
capaz de utilizar las herramientas de desarrollo estándares para conseguir esto,
más que manualmente applying y siguiendo remiendos encima servidores de
producción, es una ayuda preciosa y un beneficio de tiempo. También puedes ser
utilizando el Odoo rama de Asociación Comunitaria de Odoo, (https://
github.com/OCA/OCB) Para qué ninguno paquetes están proporcionados.

Copias de seguridad
La receta no cubre copias de seguridad. En el muy menos, tendrías que tener el cron
tarea en el servidor que corre una copia de seguridad diaria. Una solución sencilla y básica
es para editar el crontab archivo cuando raíz por running crontab -e y para añadir las
líneas siguientes:
@Diario su postgres -c pg_dumpall | gzip > /copias de
seguridad/postgresql-$(fecha +%u).dump.gz
@Alquitrán diario czf /copias de seguridad/odoo-datos-$(fecha
+%u).tgz /Casa/odoo/odoo-prod/dato/de proyecto

350
Capítulo 16

No olvida para crear el /directorio de copias de seguridad. Los archivos de copia de


seguridad no tendrían que ser almacenados en el mismo disco duro, e idealmente, serían
mirrored en un servidor en un diferente físico
Ubicación. Control estas copias de seguridad en una base regular; teniendo copias de
seguridad que te no puede restaurar when les necesitas es inútil.
La solución propuesta es a mantiene copias de seguridad diarias de los últimos 7 días, el cual
te significas perderá un día de trabajo en caso de un problema. hay más adelantó las
soluciones disponibles para
PostgreSQL Aquello deja punto-en-recuperación de tiempo. Encontrarás más información
sobre este en el libro PostgreSQL 9 Admin Recetario, Packt Publicando. De modo parecido,
hay muchas herramientas de Linux, como duplicidad
(http://duplicity.nongnu.org/), el cual te puede utilizar para copias de seguridad de
archivo que dejan administración fácil.

Ve también
Para más información en el Odoo rama de Asociación Comunitaria de Odoo, ver la receta
Instalación fácil de fuente en Capítulo 1, Instalando el Odoo Entorno de Desarrollo.

Adaptando el archivo de
configuración para producción
En Capítulo 1, Instalando el Odoo Entorno de Desarrollo hemos visto cómo para salvar la
configuración del caso en un archivo. Utilizamos el default valores para muchos parámetros,
y si has seguido el Estandarizar vuestro caso directory receta de diseño en Capítulo 2,
Dirigiendo Odoo Casos de Servidor, así como la receta anterior para la instalación de
producción, ahora tendrías que tener que archivo de configuración misma en el entorno de
producción. Estos espectáculos de receta cómo para derivar un configuratel ión archiva
aquello es propio para uso en producción.

Preparándose
Suponemos que te ha instalado Odoo en el servidor de producción con la receta anterior,
Instala Odoo para producción. Suponemos que serás correr PostgreSQL en el mismo
servidor cuando Odoo.

Puedes querer instalar el pwgen utilidad para generar contraseñas aleatorias.


Estamos describiendo los pasos aquí como si les corrías encima el servidor de producción,
pero también pueden ser ejecutados en vuestro servidor de desarrollo, desde el archivo de
configuración nuevo is añadió al Git repositorio del proyecto que utilizamos para desplegar en
el servidor de producción.
351
Despliegue de servidor

Cómo para hacerlo…


Para adaptar el archivo de configuración para producción, necesitas seguir estos pasos:

1. Crear un archivo de configuración nuevo para la producción basada en el


archivo de desarrollo: $ cd ~/odoo-prod/proyecto
$ cp Desarrollo.conf Producción.conf

2. Editar el archivo de configuración de la producción.


3. Cambio el addons camino para emparejar el directorio de base de la producción:
addons_Casa = /de camino/odoo/odoo-
prod/proyecto/src/odoo/addons,/casa/ odoo/odoo-
prod/proyecto/src/odoo/openerp/addons,/casa/odoo/odoo-
prod/proyecto/src/socio-contacto

4. Cambio el directorio de dato:


Dato_dir = /casa/odoo/odoo-prod/dato/de proyecto

5. Cambio el camino de registro del servidor para emparejar la


producción base directorio: logfile = /casa/odoo/odoo-
prod/registros/de proyecto/odoo.Registro

6. Configura rotación de
registro: logrotate =
Cierto

7. Configurar el logging handlers:


nivel_de registro =
advierte
Registro_handler =
:AVISO,werkzeug:CRÍTICO,openerp.Servicio. Servidor:INFO

8. Adaptar la base de datos


conectaparámetros de ión: db_anfitrión
= Falso
db_maxconn = 64
db_nombre = odoo-
proyectar db_la
contraseña = Falsa
db_portuario = Falso
db_plantilla = de
plantilla1 db_el usuario
= Falso
9. Configurar el filtro de base de datos, e inutilizar listado de
base de datos: dbfilter = odoo-proyectar$
Lista_db = Falso

352
Capítulo 16

10. Cambio la contraseña maestra:


admin_La contraseña = utiliza una contraseña aleatoria generada con
p. ej. pwgen

11. Configura Odoo para correr con


trabajadores: trabajadores = 4
Memoria_de límite_dura = 4294967296 #
4 GB memoria_de límite_blanda =
671088640 # 640MB límite_request =
8192
Tiempo_de límite_cpu =
120 tiempo_de
límite_real = 300

12. Sólo escuchar en la interfaz de red local:


xmlrpc_interfaz = 127.0.0.1
netrpc_interfaz = 127.0.0.1

13. Salvar el archivo, y añadirlo al Git repositorio:


$ git añadir producción.conf
$ git Cometer -m "añade production archivo de configuración"

Cómo trabaja…
La mayoría de los parámetros mostrados en esta receta está explicada en el Dirigir
Odoo receta de casos del servidor en Capítulo 1, Instalando el Odoo Entorno de
Desarrollo.
En pasos 3, 4, y 5, cambiamos el addons camino unnd el archivo de registro. En caso estás
desarrollando en un entorno con el mismo diseño como el entorno de producción, esto está
requerido porque Odoo espera caminos absolutos en el archivo de configuración.
Paso 6 habilita rotación de registro. Esto causará Odoo a configure el logging módulo a
archivo los registros de servidor en una base diaria, y para mantener los registros viejos
para 30 días. Esto es útil encima servidores de producción para evitar registros finalmente
consumiendo todo el disco disponible espacio.
Paso 7 configura el logging nivel. El encuadre propuesto es muy conservador y sólo mensajes de
registro con al menos el nivel de AVISO, excepto werkzeug (CRÍTICO) y openerp.
Servicio.Servidor (INFO). Para más información en el registro que filtra, refiere a Capítulo
7,
Depuración y Testaje Automatizado, whantes de ti encontrará la receta, Produciendo
registros de servidor para ayudar depurar métodos. Siente libre de poner a punto esto a
vuestro gusto.
Paso 8 configura los encuadres de base de datos. Esto trabajará si estás corriendo el
PostgreSQL servidor de base de datos localmente y lo ha instalado tan explained en la
receta anterior. Si estás corriendo PostgreSQL en un servidor diferente, necesitarás
reemplazar los valores Falsos con los encuadres de conexión apropiados para
vuestro caso de base de datos.

353
Despliegue de servidor

Paso 9 restringe la base de datos unvailable al caso por configurar un filtro de base de datos.
También inutilizamos el listado de base de datos, el cual no es estrictamente necesario
dado que la expresión regular pusimos en dbfilter sólo puede emparejar uno base de
datos sola. Es todavía una cosa buena para hacer aun así, para evitar mostrando la lista
de bases de datos a cualquiera, y para evitar los usuarios que conectan a la base de datos
incorrecta.
Paso 10 conjuntos un nontrivial contraseña maestra para el caso. La contraseña maestra
está utilizada para administración de base de datos a través de la interfaz de usuario, y
unos cuantos comunitario addons también utiliza él para seguridad extra antes de actuar
acciones que puede dirigir a pérdida de dato. Realmente necesitas poner esto a un
nontrivial valor. Proponemos utilizar el pwgen utilidad para generar una contraseña
aleatoria, pero cualquiera otro método esun lso válido.
Paso 11 configura Odoo para trabajar con trabajadores . En este modo, Odoo creará un
número de procesos de trabajador (en este ejemplo, 4) para manejar peticiones de HTTP.
Esto tiene varias ventajas sobre el default configuración en qué la petición que maneja está
actuado en hilos separados, los cuales están dados como sigue:
f Las peticiones pueden ser manejadas en paralelo, haciendo uso mejor de núcleos
múltiples o CPUs en el servidor (hilos de Pitón están penalizados por la existencia
de las Cerraduras de Intérprete Globales (GIL) ent él intérprete de Pitón).
f Es posible de rescindir uno de los trabajadores que dependen de consumo de
recurso.
La mesa siguiente da el varios recurso limita que puede ser configurado:

Parámetro Sugerido Descripción


Valor
Memoria_de
límite_dura 4294967296 Esto es la cantidad máxima de RAM un trabajador
Ser capaz de destinar. Recomendamos utilizar 4
GB cuando
Algunos procesa lanzados por Odoo puede destinar
Algunos cantidades grandes de RAM.
Memoria_de
límite_blanda 671088640 Si un trabajador acaba consumir más de este limit
(640 MB en nuestro encuadre), sea rescindido
después de que
Acaba procesar la petición actual.
Un trabajador será rescindido después de haber
Petición_de límite 8192 procesado
Estas muchas peticiones.
Tiempo_de
límite_cpu 120 Esto es la cantidad máxima de CPU time dejó
Para procesar una petición.
Tiempo_de Esto es la cantidad máxima de tiempo de reloj de
límite_real 300 la pared
Dejado para procesar una petición.
Paso 12 configura el interno Odoo servidor de web a sólo escuchar en la interfaz local. Esto
significa el caso not ser reachable de otros servidores. Esto nos habilito para configurar un
inverso proxy en el mismo servidor para acceder el servidor y a la fuerza encriptó conexiones.
Tomar una mirada en el Configurar un inverso proxy y SSL receta más tarde en este capítulo.

354
Chapter 16

Allí ha más…
Cuándo corriendo con trabajadores, puedes encontrar algunos emite concretos a este modo:

fSi consigues errores extraños cuándo corriendo con trabajadores, con lessco
wkhtmltopdfno trabajando tan pretendidos (por ejemplo, prematuramente
saliendo con un -11 o -6 estado), entonces probablemente tienes memoria_de
límite_conjunto duro a un valor que es demasiado abajo. Prueba levantar lo un
poco, cuando el default el valor es notoriamente demasiado abajo.
fSi consigues timeout errores cuándo actuando operaciones largas (esto incluye CSV
importacionesy exportacións y addon instalaciones de módulo), prueba aumentar
el tiempo_de límite_cpu y tiempo_de límite_parámetros reales, tan allí
demasiado el default el valor es bastante abajo. Si tienes un inverso proxy, puedes
querer comprobar su timeout límite también (a pesar de que esto no impedirá elt
ransactions de completar).
fSi vuestro caso consigue completamente enganchado cuándo imprimiendo
informes, prueba levantar el númerode trabajadores. Esto puede ser un punto
muerto causado por wkhtmltopdf bloqueando arriba todos los trabajadores
disponibles mientras imprimiendo.

De todas formas, siempre validatar el setup antes de ir a


producción, y recordar para probar imprimiendo informes cuándo
habilitando trabajadores.

Instalado Odoo como servicio de sistema


Para un caso de producción, es muy importante que el Odoo el servidor empieza cuándo
el ordenador reboots. En current sistemas de Linux, hay maneras diferentes de
conseguir este, dependiendo de la distribución y el servidor setup; cualquiera es un init
guión, o un systemd configuración. Estos espectáculos de receta cómo para hacer
ambos.

Preparándose
Suponemos que seguiste el abetost dos recetas para instalar y configurar vuestro Odoo caso.
Especialmente la fuente desplegada de Odoo, el cual es en /casa/odoo/odoo-
prod/proyecto/ src/odoo/, y el archivo de configuración del caso, el cual es en
/casa/odoo/odoo-prod/producción/de proyecto.conf. Los guiones también hace
uso del inicio-odoo el guión creado en paso 9 del Instalar Odoo para receta de
producción.
Primero necesitarás descubrir qué sistema de inicialización está corriendo en vuestro
sistema. Para este, corrido el siguiente:
$ dpkg -l systemd
Si la última línea de inicios de producción con ii systemd, entonces systemd es disponible
en vuestro sistema. Otherwise, probablemente estás corriendo sysvinit (en un sistema
que corre un viejo Debian variante) o upstart (en un Ubuntu-sistema basado).
355
Despliegue de servidor

Cómo para hacerlo…


Ahora que sabes qué versión del sistema de inicialización estás corriendo, puedes escoger
cómo para configurar Odoo.

Configurando systemd para empezar Odoo


Para configurar systemd para empezar Odoo, necesitas actuar los pasos siguientes:

1. Cuando raíz, crear un archivo llamó


/lib/systemd/sistema/odoo.Servicio, con los contenidos siguientes:
[Unidad]
Descripción=Odoo 9.0
Después de que=postgresql.Servicio

[Servicio]
El tipo=sencillo
Usuario=odoo
Grupo=odoo ExecStart=/casa/odoo/odoo-prod/inicio/de
cubo/del proyecto-odoo

[Instala] WantedBy=multi-
usuario.Objetivo

2. Cuando raíz, registro el servicio:


# systemctl Habilita odoo.Servicio

3. Cuando raíz, inicio el servicio:


# Servicio odoo inicio

4. Para parar el servicio, puedes correr el siguiente:


# Servicio odoo parón

Configurando sysvinit o upstart para empezar Odoo


Para configurar sysvinit o upstart para empezar Odoo, necesitas actuar los pasos
siguientes:

1. Cuando raíz, copia el init el archivo proporcionado por Odoo a /etc/init.d :


# cp src/odoo/debian/init /Etc/init.d/odoo
# chmod +x /Etc/init.d/odoo

356
Capítulo 16

2. Cuando raíz, edita que file para cambiar las variables de entorno definieron en la
parte superior del guión (sólo listamos los cuáles necesitan cambiar como sigue,
con los valores apropiados):
DAEMON=/Casa/odoo/odoo-prod/inicio/de cubo/del proyecto-odoo

3. En el mismo archivo, también modificar el _inicio


functiencima como sigue: inicio _de función() {
Inicio-parón-daemon --inicio --tranquilo --pidfile
$PIDFILE --chuid $USUARIO:$USUARIO --de fondo --marca-pidfile
--exec $DAEMON
}

4. Cuando raíz, registro el daemon con sysvinit o upstart:


# Actualización-rc.d odoo defaults

5. Cuando raíz, inicio the servicio:


# /Etc/init.d/odoo Inicio

6. Si quieres parar el servicio, corres el siguiente:


# /Etc/init.d/odoo Parón

Cómo trabaja…
Las tres configuraciones, systemd, sysvinit, y upstart , uso algunos archivos de
configuración o guiones para saber cuál programa must corrido cuándo las botas de servidor.
Las configuraciones proporcionadas en la receta necesitará adaptaciones pequeñas para
emparejar los caminos de vuestro caso.

No olvida a reboot vuestro servidor y control que Odoo


es correctamente empezó!

Allí ha más…
Si estás utilizando el buildout el método descrito en el Uso buildout para repeatable receta
de complexiones, necesitarás adaptar los caminos para utilizar el inicio_odoo el guión
creado por la receta.

Configurar un inverso proxy y SSL


Para evitar toda la información entre los usuarios' browsers y el Odoo servidor, aquello es para ser
enviado claro sobre la red, es necesario de utilizar el protocolo de HTTPS que encripta los
intercambios. Odoo Puede no este natively, y es necesario de configurar un inverso proxy que
manejará la encriptación y decryption en behalf del Odoo servidor. Estos espectáculos de receta
Cómo para utilizar nginx (http://nginx.net) para este.
357
Despliegue de servidor

Preparándose
Tendrías que saber el nombre público del servidor y configurar vuestro DNS
consiguientemente. En esta receta, utilizaremos odoo.example.com cuando el nombre
de vuestro servidor.
Si quieres vuestro Odoo caso para ser visible por todos los navegadores, necesitarás
conseguir un SSL el certificado firmado por una Autoridad de Certificación reconocida
(CA). Utilizando un self-el certificado firmado también puede ser hecho para trabajar, pero
los navegadores modernos tienden para rechazar estos.
Para generar un SSL llave, puedes utilizar el proceso siguiente:

1. Instala openssl:
$ sudo Apto-conseguir instalar openssl

2. Generar la llave para vuestro


servidor: $ mkdir ~/sslkey
$ openssl genrsa -Fuera de /sslkey/servidor.Clave ~2048

3. Generar una petición de fichaje:


$ openssl req -Nuevo -clave ~/sslkey/servidor.Clave -fuera de
/sslkey/servidor. ~csr

4. La orden de preceder te preguntará una serie de cuestiones sobre vuestra compañía y


vuestro Odoo servidor URL. No consigue estos incorrecto o vuestro certificado será
unusable.
5. Serás capaz de enviar el archivo, ~/sslkey/servidor.csr, a una Autoridad de
Certificación (CA) de vuestra elección. El CA te devolverá un archivo servidor
llamado.crt, El cual utilizaremos en la receta.

Cómo para hacer it…


Para acceder vuestro caso que utiliza HTTPS vía nginx, necesitas seguir estos pasos:

1. Cuando raíz, instala nginx:


# Apto-conseguir instalar nginx

2. Cuando raíz, crear un archivo de configuración en /etc/nginx/sitios-


disponibles/odoo-80: servidor {
Escucha [::]:80 ipv6sólo=fuera;
nombre_de servidor
odoo.example.com;
Registro_de acceso
/var/registro/nginx/odoo80.Acceso.El registro
combinó; registro_de error
/var/registro/nginx/odoo80.Error.Registro;

358
Capítulo 16
Ubicación / {
Reescribe ^/(.*) https://odoo.example.com:443/$1 permanente;
}
}

3. Crear un configuratarchivo de ión en /etc/nginx/sitios-


disponibles/odoo-443: servidor {
Escucha [::]:443
ipv6sólo=fuera; nombre_de
servidor odoo.example.com;
ssl encima;
ssl_Certificado /etc/nginx/ssl/servidor.crt;
ssl_Llave_de certificado
/etc/nginx/ssl/servidor.Clave; registro_de acceso
/var/registro/nginx/odoo443.access.El registro
combinó; registro_de error
/var/registro/nginx/odoo443.Error.Registro;
cliente_max_medida_de cuerpo 128M;
gzip Encima;
proxy_leído_timeout 600s;
Índice de índice.html Índice.htm Índice.php;

Añade_el encabezamiento Estricto-Transporte-Seguridad


"max-edad=31536000"; proxy_Anfitrión_de encabezamiento
del conjunto $anfitrión_de http;
proxy_Encabezamiento_de conjunto X-Real-IP $remoto_addr;
proxy_Encabezamiento_de conjunto X-Adelante-Para
$proxy_añade_x_enviado_para; proxy_encabezamiento_de conjunto
X-Enviado-Proto https; proxy_encabezamiento_de conjunto X-
Enviado-Anfitrión $anfitrión_de http;

Ubicación / {
proxy_Http de
pase://localhost:8069;
proxy_leído_timeout 6h;
proxy_conecta_timeout 5s;
proxy_Redirige http://$http_https/
anfitrión://$anfitrión:$puerto_de servidor/;
añade_encabezamiento X-Estático no;
proxy_buffer_Medida 64k;
proxy_buffering fuera;
proxy_buffers 4 64k;
proxy_ocupado_buffers_medida
64k;

359
Despliegue de
servidor

proxy_intercept_Errores encima;
}

Ubicación /longpolling/ { proxy_http


de pase://localhost:8072;
}

Ubicación ~ /[un-zA-Z0-9_-
]*/estático/ { proxy_http de
pase://localhost:8069;
proxy_cache_válido 200 60m;
proxy_buffering encima;
Expira 864000;
}
}

4. Cuando raíz, enlace el configuratiencima archivo en /etc/nginx/sitios-


habilitó/:
# ln -s /Etc/nginx/sitios-disponibles/odoo80
/etc/nginx/sitios-habilitados/odoo80
# ln -s /Etc/nginx/sitios-disponibles/odoo443
/etc/nginx/sitios-habilitados/odoo443

5. Cuando raíz, saca /etc/nginx/sitios-habilitados/default:


# rm /Etc/nginx/sitios-habilitado/default

6. Cuando raíz, copia el ssl certificado y llave de servidor a los directorios apropiados
# mkdir -p /Etc/nginx/ssl
# chown www-Datos /etc/nginx/ssl
# mv Servidor.Servidor clave.crt /Etc/nginx/ssl
# chmod 710 /etc/nginx/ssl
# chown Raíz:www-datos /etc/nginx/ssl/*
# chmod 640 /etc/nginx/ssl/*

7. Cuando Odoo, editar el archivo de configuración de la producción del caso para


habilitar proxy_modo: proxy_el modo = Cierto

8. Cuando raíz, retomar vuestro odoo caso y nginx :


# Servicio odoo retoma
# Servicio nginx retoma
360
Capítulo 16

Cómo trabaja…
Estamos utilizando nginx como HTTP inverso proxy. Incoming HTTP y conexiones de HTTPS
están manejados por nginx, el cual delega el procesamiento de las peticiones al Odoo
servidor. El
Odoo El servidor está configurado a sólo escuchar en el lugareño loopback interface
(127.0.0.1) en portuario 8069 para peticiones normales (xmlrpc_portuarios) y puerto
8072 para el largo encuestando peticiones (longpolling_portuarios). Puedes necesitar
adaptar los números portuarios a vuestra configuración.

La receta instala dos archivos. El primer ene es la configuración para incoming conexiones en
portuarios
80 utilizando el protocolo de HTTP. No queremos estos porque son en texto claro,
significando que las contraseñas pueden ser husmeadas. Por tanto, instalamos nginx para
redirigir el URLs permanentemente a puerto 443 using el protocolo de HTTPS encriptado.
El segundo archivo es un poco más complejo y configura la manera nginx tendría que
manejar las conexiones que utilizan el protocolo de HTTPS:
fEl primer bloque de configuración configura el SSL protocolo, la llave de
encriptación, y certificado, cuandow ell como la ubicación del archivo de
registro.
fLos segundos conjuntos de bloque algunos encabezamientos en las peticiones
para manejar el apropiados inversosproxying encima HTTPS.
fElbloque /de ubicación define el default procesamiento de incoming peticiones;
seránproxied al Odoo servidor listening en portuario 8069.
fLa ubicación /longpollingconsultas de mangos del bloque hicieron en URLs
empezando con /longpolling, los cuales son entonces enviados a Odoo en
portuarios 8072. Estas conexiones están utilizadas por el autobús addon módulo para
enviar notificaciones al cliente de web.
fLa ubicación ~ /[un-zA-Z0-9_-]*/el bloque/estático utiliza una expresión
regularpara emparejar el URLs de los archivos estáticos de Odoo módulos. Estos
archivos son raramente actualizados, y tan preguntamos nginx a cache les para aligerar
la carga en el Odoo servidor.

361
Despliegue de servidor

Allí ha más…
Este foco de receta en el nginx configuración. Puedes ser más familiar con otras
herramientas como el servidor de web del apache y mod_proxy . En este caso,
naturalmente puedes utilizar estos para conseguir un similar setup.

Ve también
fPara másinformación sobre el varios nginx opciones de configuración,
vehttp://nginx.org/en/docs/.
fPara un preceptoral en la configuración de apache2 como inverso proxy y el uso de
unacertificación personal authority, tomar una mirada en
http://antiun.github.io/odoo-
Inverso-proxy-howto/.

Uso buildout para repeatable complexiones


Tan lejos, nosotros have manualmente sido instalando nuestros casos. Estos gritos para
automatización, y quizás te ya ha escrito un guión de concha para descargar la versión apropiada
del addons vuestras necesidades de caso y streamlined el proceso. Resulta que hay una
herramienta significó to ayuda con hacer este llamado buildout. Buildout Es una Pitón-sistema de
complexión basada para crear, ensamblaje, y desplegando aplicaciones de partes múltiples,
algunos de los cuales pueden ser no-Pitón-basó. Deja creas un buildout configuración y
reproducir els ame software más tarde.

Estos espectáculos de receta cómo puedes empezar utilizar buildout para asegurarte ha
igual setup en el desarrollo y servidores de producción.

Preparándose
Suponemos que vuestro caso sólo tiene una dependencia en el servidor-proyecto de
herramientas del
Odoo Asociación Comunitaria, y que vuestro usuario-concreto addon los módulos
están viviendo en el locales/addons subdirectorio del proyecto.
También te esperamos para tener instalado las dependencias de complexión de Odoo.
Refiere a pasos 1 a 3 del Instalar Odoo para producción recipe en este capítulo. Esta receta
es mejor utilizado primero en una máquina de desarrollo y más tarde desplegado en un
servidor de producción.
362
Capítulo 16

Cómo para hacerlo…


Para utilizar buildout para construir vuestro proyecto, necesitas seguir estos pasos:
1. On Vuestro servidor de desarrollo, crear un directorio de
trabajo nuevo: $ mkdir ~/odoo-dev/proyecto-
buildout
$ cd ~/odoo-dev/Proyecto-buildout

2. Crear un archivo llamó buildout.cfg:


[buildout]
Partes =
odoo
Encuentra-enlaces = http://download.gna.org/pychart/

[odoo]
Receta =
anybox.Receta.odoo:Servidor OCA =
https://github.com/oca
Versión = git https://github.com/odoo/odoo.git odoo 9.0
profundidad=1 addons = git ${odoo:OCA}/servidor-herramientas.git
Separa/servidor-herramientas 9.0 git ${odoo:OCA}/socio-
contacto.git Separa/socio-contacto 9.0
Local local/addons

Opciones.Memoria_de límite_dura =
4294967296 opciones.Memoria_de
límite_blanda = 671088640
opciones.Petición_de límite = 8192
opciones.Tiempo_de límite_cpu = 120
opciones.Tiempo_de límite_real = 300
opciones.xmlrpc_Puerto = 8069
opciones.longpolling_Puerto = 8072
opciones.Trabajadores = 0

[versions]
zc.buildout = 2.5.0
anybox.buildout.odoo = 1.9.1
setuptools = 19.7

Babel = 1.3
Jinja2 = 2.7.3
Mako = 1.0.1
MarkupSafe = 0.23
Almohada = 2.7.0
363
Despliegue de
servidor

Pitón-Gráfico =
1.39 PyYAML = 3.11
Werkzeug = 0.9.6
argparse = 1.2.1
decorator = 3.4.0
docutils = 0.12
feedparser = 5.1.3
gdata = 2.0.18
gevent = 1.0.2
greenlet = 0.4.7
jcconv = 0.2.3 lxml
= 3.4.1
Simulado = 1.0.1
ofxparse = 0.14
passlib = 1.6.2
psutil = 2.2.0
psycogreen = 1.0
psycopg2 = 2.5.4
pyPdf = 1.13
pydot = 1.0.2
pyparsing = 2.0.3
pyserial = 2.7
Pitón-dateutil = 2.4.0
pitón-ldap = 2.4.19
pitón-openid = 2.2.5
pytz = 2014.10
pyusb = 1.0.0b2
qrcode = 5.1
reportlab =
3.1.44 peticiones
= 2.6.0 seis =
1.9.0 suds-jurko
= 0.6 vatnumber =
1.2 vobject =
0.6.6 wsgiref =
0.1.2 xlwt =
0.7.5
364
Capítulo 16

3. Crear un archivo de configuración para el entorno de producción:


[buildout]
Extiende = buildout.cfg

[odoo]
Opciones.Memoria_de límite_dura =
4294967296 opciones.Memoria_de
límite_blanda = 671088640
opciones.Petición_de límite = 8192
opciones.Tiempo_de límite_cpu = 120
opciones.Tiempo_de límite_real = 300
opciones.Trabajadores = 4

Opciones.Dato_dir = dato/de proyecto

Opciones.xmlrpc_Interfaz = 127.0.0.1
opciones.netrpc_Interfaz = 127.0.0.1
opciones.xmlrpc_Puerto = 8069
opciones.longpolling_Puerto = 8072

Opciones.log_El nivel = advierte


Opciones.Registro_handler =
:AVISO,werkzeug:CRÍTICO,openerp.Servicio. Servidor:INFO

Opciones.admin_La contraseña = genera con pwgen

Opciones.listdb = Falso
options.db_anfitrión = Falso
options.db_portuario = Falso
options.db_el usuario = Falso
options.db_nombre = odoo_opciones
de proyecto.dbfilter =
^odoo_Proyecto$ opciones.proxy_El
modo = Cierto
365
Despliegue de
servidor

4. Crear un archivo de configuración para el entorno de desarrollo:


[buildout]
Extiende = buildout.cfg

[odoo]
options.db_Nombre = odoo_dev
optaiones.dbfilter =
^odoo_dev$ Opciones.Nivel_de
registro = info

5. Crear un virtualenv sin setuptools: $


virtualenv sandbox --no-setuptools

6. Descarga la versión actual del bootstrap.py archivo:


$ wget https://raw.github.com/buildout/buildout/master/bootstrap/
Abucheartstrap.py

7. Corrido el bootstrap.py guión:


$ sandbox/Pitón/de cubo bootstrap.py

8. En vuestra máquina de desarrollo, puedes crear un entorno de desarrollo por


correr el siguiente:
$ Cubo/buildout -c dev.cfg

9. En el servidor de producción, crearías un entorno de producción por correr el


siguiente:
$ Cubo/buildout -c prod.cfg

10. Para empezar el caso, corrido el


siguiente: $ inicio/de cubo_odoo

11. Cometer los archivos a


Git: $ git init
$ git Añadir buildout.cfg prod.cfg dev.cfg bootstrap.py
Local/addons $ git cometer -m "initialize proyecto con buildout"
366
Capítulo 16

Cómo trabaja…
Buildout Trabajos por procesar un archivo de configuración, el cual se apellida
buildout.cfg Por default.
Este archivo utiliza una sintaxis cierra a ConfigParser (con unas cuantas extensiones) para
describir el entorno de objetivo deseado. Hay uno sección obligatoria, [buildout], el cual
contiene una entrada de partes que lista las secciones para procesar. La mayoría de secciones
tienen una entrada de receta que da el nombre de un buildout receta para utilizar para
construir la sección. Hay muchas recetas disponibles (toma un
Mirada en http://www.buildout.org/en/latest/docs/recipelist.html para un
listado parcial), y las recetas diferentes pueden ser combinadas en un archivo de
configuración solo. Each La receta apoya sus encuadres de configuración propios. Las
recetas son módulos de Pitón , normalmente hechos disponibles de PyPI.
Buildout Archivos de configuración son extensibles y soporte parameterization:

fUn archivo de configuración puedeextenderotro; configuración settings está


añadido o overwritten por el archivo de extender.
fEncuadres de configuración pueden referir al valor de otros encuadres
que utilizan el${sección:sintaxis} de nombre.
fEn paso 1, preparamos nuestra basebuildout.cfgArchivo de configuración.
Definimos una secciónllamada [odoo] y poner el anybox.Receta.odoo
Parámetro como el buildout receta en cargo para esta sección. Aquí es los encuadres
utilizamos:
‰‰ Versión: Esto define el Odoo versión queremos. Aquí, estamos utilizando
la versión más tardía de la 9.0 rama en GitHub. Las opciones de
profundidad limitan el Git profundidad de clon para solicitar la instalación.
‰‰ OCA: Esto es un encuadre hecho de encargo utilizó para simplificar el URLs
del OCA addons estamos listando en los encuadres siguientes, utilizando el
‰‰
${odoo:OCA} variable.
addons: Esto lista el addons directorios para instalar, uno por uno. La
sintaxis es protocolo URL opciones de revisión del destino. El
Git el protocolo utilizará Git para clonar un repositorio. El protocolo local
utilizará un directorio local (y la revisión no tiene que ser proporcionada en
este caso). Otro available los protocolos son hg (para mercurial repositorios),
svn (subversion), bzr (bazar). La revisión puede ser una etiqueta , una rama,
o un cometer identificador.
El [versiones] la sección es un estandarizado buildout la sección utilizó para especificar
las versiones de la Pitón dependencies que será instalado en el entorno. Es importante de
fijar
La versión de zc.buildout , anybox.buildout.odoo, y setuptools en esta sección para
asegurar el repeatability de la complexión, el cual es qué hacemos en las primeras dos líneas de
la sección. El unnybox.buildout.odoo La receta es capaz de encontrar los nombres de las
dependencias del Odoo versión de servidor, pero no las versiones. Para generar esta lista,
copiamos los requisitos.txt Archivo para el Odoo codebase y reemplazó el == operador
con = .

367
Despliegue de servidor

El prod.cfg Y dev.cfg Los archivos extienden la configuración de base definida en


buildout.cfg. En el [odoo] sección, ellos ambos definen encuadres con los nombres que
empiezan con opciones . (Mente el punto): buildout utilizará estos cuando generando un
configuration archivo para el caso con las opciones puestas tan especificados en el archivo de
configuración. Si has leído la receta que Adapta el archivo de configuración para producción en
este capítulo, el prod.cfg El archivo tendría que ser familiar.

Para asegurar que el buildout el entorno es insulated de la Pitón de sistema, utilizamos un


virtualenv (llamados sandbox en esta receta) configuró a no tener setuptools disponible.
Utilizamos este virtualenv para correr el bootstrap.py guión que descargamos del
buildout código de fuente repository. La función de bootstrap.py es para preparar cosas para
buildout para trabajar, incluyendo instalando buildout él. Un guión, cubo/buildout, está
creado en el directorio de la complexión para correr buildout.
Entonces puedes dirigir vuestro buildout configuración en un sistema de administración de
la versión como Git. Está recomendado que almacenas el bootstrap.py archivo junto
con el buildout archivo de configuración; este archivo evoluciona con buildout, y desde
entonces estamos congelando la versión de buildout en el archivo de configuración,
necesitamos a keep el bootstrap.py archivar que sabemos trabajará con esta versión.

Para correr buildout, justo ejecutar el cubo/buildout guión con el -c opción para
especificar un archivo de configuración. Esto hará varias cosas:
f Odoo Consigue instalado en el subdirectorio/ de partes
fEl especificado addons está instalado en el subdirectorio especificado (
recomendamos que utilizas partes/ para este también)
fLas dependencias de Odoo y cualesquier dependencias adicionales están
instaladas ensubdirectorio/ de huevos
fUn archivo de configuración está creado enetc/odoo.cfgCon el valor
apropiado paraaddons_el camino y todas las opciones especificaron en el
buildout configuraciones
fUn helper iniciode cubo/del guión_odooestá creado; utiliza el archivo de
configuración generadoy las dependencias de Pitón instaladas

Allí ha more…
Si uno addon módulo que te la necesidad requiere una dependencia de Pitón externa, lo
puedes añadir al [odoo] la sección que utiliza los huevos que ponen. Para caso, para añadir
unicodecsv al buildout, uso el siguiente:
[odoo]
Huevos += unicodecsv

[Versiones]
unicodecsv = 0.14.1
368
Capítulo 16

Provisional fusiona
Durante desarrollo, pueda ser útil de fusionar peticiones de atracción pendiente en los
varios proyectos utilizaron por el proyecto. El buildout la receta apoya esto a través del
fusiona opción. Suponer vuestro proyecto utiliza OCA/socio-contacto y OCA/producto-
atributo, y necesitas fusionar el PR 237 y 249 encima socio-contacto y el PR 132 encima
atributo de producto, entonces puedes escribir el siguiendo en vuestro buildout archivo de
configuración:
[odoo]
OCA = https://github.com/oca
version = git https://github.com/odoo/odoo.git odoo 9.0 profundidad=1
addons = git ${odoo:OCA}/socio-contacto.git Separa/socio-contacto 9.0
git ${odoo:OCA}/Producto-atributo.git Separa/producto-atributo
9.0
Fusiona = git socio de partes/del origen-atracción de
contacto/237/cabeza git socio de partes/del origen-
atracción de contacto/249/cabeza
git Producto de partes/del origen-atracción de atributo/132/cabeza

La sintaxis para el fusionar la opción que utiliza el git el protocolo es repositorio> <local remoto
<> <refspec>. Utilizamos aquí la referencia para atracción pide proporcionada por GitHub.

Una palabra de amonestación


Esta característica es muy útil durante desarrollo pero tendría que ser
evitado para despliegue en producción. El fusionó las ramas pueden
evolucionar y ser rebased u overwritten sin aviso. Es mejor que vuestro
despliegue depende de no-fusionado PR con objeto de utilizar un
tenedor personal del proyecto encima que te hará el te fusiona para
asegurar que consigues repeatable complexiones. También, nota que el
buildout congelación-a opción, el cual está explicado luego, no
trabaja con fusiona .

Congelando un buildout
A ease despliegue, es posible de utilizar algunos adelantaron órdenes. La congelación-a la
opción puede soler generar un buildout archivo de configuración que congelaciones las
revisiones de Odoo y todo el addons:
$ Cubo/buildout -c prod.cfg -o odoo:Congelación-a=congelado-prod.cfg

You Puede entonces corrido buildout con el congelado-prod.cfg Archivo para conseguir
las versiones mismas exactas de los archivos.
También puedes extraer el código de fuente a un directorio separado, con el extracto-
descargas-a opción:.
$ Cubo/buildout -c congelado-prod.cfg \
-o odoo:Extracto-downloads-a=../Producción
369
Despliegue de servidor

La producción de directorio ahora contiene una liberación.cfg Archivo, y un


directorio/ de partes con el código de fuente (pero no el git historia). Si el servidor de
objetivo está corriendo la misma versión de Linux como el server estás trabajando encima,
puedes desplegar el entorno de producción sin compilar cualquier dependencia por actuar
los pasos siguientes:

1. Copia el archivo requerido al directorio/ de producción:


$ cp -r Desarrolla-huevos de huevos buildout.cfg prod.cfg
bootstrap.py \
../Producción

2. Marca un archivo de aquel


directorio: $ cd ..
$ Alquitrán cjf production-1.0.tar.bz2

3. Copia que archivo en el servidor de producción que utiliza un procedimiento


adecuado (llave de USB o rsync , para caso).
4. En el servidor de producción, desempaquetar el archivo e instalar la versión con el
siguiente: $ alquitrán xf production-1.0.tar.bz2
$ cd Producción
$ virtualenv sandbox --No-setuptools $
sandbox/pitón/de cubo bootstrap.py
$ Cubo/buildout -c liberación.cfg

Ve también
f La documentación llena para el buildout la receta es disponible en http://docs.
anybox.fr/anybox.recipe.odoo/current/index.html.
370
Utilizado, para elementos de forma dinámica
207
Automatizó acciones
Utilizando, encima el acontecimiento
condiciona 288-291 utilizando,
puntualmente condiciona 283-287

Símbolos
@api.Un decorator 98, 99

Un
Modelos abstractos
Utilizando, para el modelo reutilizable
presenta 89-91
Control de acceso lista
127 acciones
ir.Acciones.Ventana_de
acto.Vista 185 parámetros,
paso 190-193 vista concreta,
abriendo 184, 185
addon Módulo
Cambios, applying 42, 43
creando 48, 49
El dato archiva 54
Estructura de archivo,
organizando 52-55 instalando
48, 49
Instalando, de GitHub 40, 41
lista, actualizando 31-33
manifiesta, acabado 49-52
Código de pitón
54 versus addon
29 ventajas de
web 54
addons El camino
que configura 30,
31
addon updates 229-231
API Código
Viejo API código, porting a nuevo API
143-151
API decorators
Definiendo 96-98
attrs Atributo
Depuración 340-343
pruebas, escribiendo para
336-339
Cliente-lado QWeb las
plantillas que utilizan

Índice
331-333
Línea de ordeni nterface
157 repositorio comunitario
URL 330
B
backups 351 371
base_suspende_se
guridad
URL 127
bootstrap
URL 318
buildou
t
Aproxi
mada
ment
e 362
Helado 369, 370
provisional
mergess 369 URL
367, 370
Utilizando, para repeatable complexiones
362-368
Construido-en workflows
Inspeccionando 291-294
Lógica empresarial
En modelo, extendiendo 114-117
Botones
Añadiendo, a formas 189, 190

C
El calendario ve
212, 213 categoría
URL 51
Autoridad de certificación (CA)
Aproximadamente 358
Personal
362
cliente-
código de
lado
Computó campos Dependencias 4
Añadiendo, a modelo 82-84 herramientas de
configurable Precisión desarrollador
Campo de flotador, utilizando con 71, 72 Activando 22-24
Configuración Documento-el estilo forma 205, 206
Adaptando, para producción 351-355
Validaciones de
constreñimiento que
añaden, a modelo 80,
81
content
Añadiendo, para formar vista 186
Contexto
Utilizado, para computar default valores
136
Nodo de contexto
203 crea()
Extendiendo 117-120
CSS
Extendiendo, para sitio web 311-313
CSV Archivos
Utilizado, para cargar dato 226,
227 hecho de encargo widgets
Creando 325-330

D
Dato
Cargando, CSV los archivos
utilizaron 226, 227 cargando,
XML archivos utilizaron 221-224
cargando, YAML los archivos
utilizaron 228, 229
Campos de dato
Añadiendo, a modelo 66-70
El dato archiva 54
Migración de dato 229-
232 datetime módulo
de Pitón
URL 275
dbfilter_de_encabeza
miento
URL 300
Debian Jessie
URL 3 decorators
97 Deferred objeto
330
Herencia de delegación
Utilizando, para copiar características a otro
modelo 91
Duplicidad La interfaz utilizó 91-
URL 351 93 siguiendo 276-280
Elementos de forma dinámica Campos
attrs Utilizó 207 En modelos, el límite que accede 241, 242
Relaciones dinámicas Archivo
Undding, campos de referencia utilizaron Configuración de caso, almacenando 19-22
86, 87 estructura para addon módulo, organizando
52-55
E Filtros
Definiendo, enr ecord listas 193-
Eficaz_readonly propiedad 195 pitfalls 196
330 emacs (po-modo) Campo de flotador
URL 264 Utilizando, con configurable precisión 71, 72
embedded Ve 207, 208 forcecreate Las
errores banderas que
Informando, a usuario utilizan 224-226
99, 100 externo IDs Formas
Utilizando 219-221 Botones, añadiendo 189, 190
parámetros, paso 190-193
F Botón de
vista de la
Características
Activando, grupo de seguridad utilizó forma 187
246-251 añadiendo a modelo, Contenido,
inheritance utilizó 87-89 copiando a añadiendo 186
otro modelo, delegación campo 188
Formas 187
General entributos 188

372
Grupos 187 Extendiendo, para sitio web 311-313
encabezami jQuery
ento 187 URL 336
Otras etiquetas 188, JSONRPC 309
189 widgets,
añadiendo 186
congelación-a opción
369

G
gettext Herramientas
Utilizando, para aliviar traducciones 264
Git
Aproximadame
nte 4
configuración 7
GitHub
addon Módulos, instalando 40,
41 URL 2, 256
Graphvi ews 213-215
Gtranslator
URL 264

H
handler
Existiendo handler, modificando 304-306
Elemento de
cabeza 313 nodo
de cabeza 313
jerarquía
Añadiendo, a modelo 78, 79
Estado de HTTP 500 100

Yo
Herencia
Utilizado, para añadir características a
modelo 87-89
Configuración de caso
storing, en archivo 19-21
Diseño de directorio del
caso standarizing 33-
35
ipdb
URL 164

J
Javascript
K Línea de orden utilizó
38 instalando 36-39
Kanban actualizando 39, 40
Tabler upgrading 36
o 271 Interfaz de web utilizó 36,
Tarjetas, mostrando en columnas 37 logging nivel 156
según estatales 211 Registro handler 156
Característica Lokalize
s 270-272 URL 264
etapas 270-
272 estado M
272
Vistas 209, 210 Manifiesta
addon El módulo manifiesta, acabado 49-52
L Elementos de carta
Añadiendo 57-61, 180-
Lengua 183 messaging
Instalando 253-256 Añadiendo 276-280
La lengua relacionó encuadres Método
Configurando 257, 258 La ejecución que localiza,
Menos depurador de Pitón utilizó
URL 314 159-164
Paquetes de distribución del Linux Depuración, por producir registros de servidor
URL 350 153-156 con contexto modificado, llamando
La lista ve 196- 128-130
198 local addon microdata
módulos URL 318

373
Modelo Copias de seguridad 350, 351
Añadiendo 55-57 Git, configuración 7
Lógica empresarial, extendiendo Instalando, para producción
114-117 computó campos, 345-348 instalando, de fuente
añadiendo 82-84 validaciones de 2-5 caso, empezando 7, 8
constreñimiento, añadiendo 80, 81 PostgreSQL Configuración 6, 7
campos de dato, añadiendo 66-70 PostgreSQL Sintonía 349, 350
Las características que añaden, la herencia
utilizó 87-89 características que copian a otro
modelo, delegación
La interfaz utilizó 91-93
campos, el límite que accede
241, 242 jerarquía, añadiendo
78, 79 métodos, definiendo
96-98 campo monetario,
añadiendo 73 orden,
definiendo 64-66
Relacionó los campos
almacenaron, exponiendo 85
campos relacionales, añadiendo
74-77 representación, definiendo
64-66 acceso de seguridad,
añadiendo 238-241
Módulo
Creando, scaffold utilizó 61, 62
Pruebas de módulo
Escritura, pruebas de unidad de la
Pitón utilizaron 168-171 escritura,
YAML utilizó 164-167
El campo monetario
que añade, a
modelo 73

N
namespaces
Utilizando 219-
221
nginx
Opciones de configuración, URL 362
URL 357
noupdate
Aproximadame
nte 317
utilizando 224-
226

O
Odoo
Servidor, dimensionamiento 348, Utilizado, para interactivamente llamando
349 instalando, cuando servicio de métodos 157, 158
sistema 355 código de fuente, Odoo superuser 127
descargando 7 código de fuente onchange métodos
versión 350 Aproximadamente 104
Empezando, systemd configurando para Llamando, encima lado de
356 empezando, sysvinit o upstart servidor 141, 142 definiendo
configurando para 138, 139
356, 357 Operadores 195
Actualizando, de fuente 25, 26
URL 323 P
Entornos virtuales (virtualenv) 5, 6
Odoo Asociación comunitaria (OCA) Parámetros
Aproximadamente 8, 29, 173 Pasado a handlers, consumiendo 302-
maintainer Herramientas de calidad, 304 paso, a acciones 190-193
utilizando 173-178 Paso, a formas 190-193
Odoo Herramientas de desarrollador Camino
Activando 22-24 accesibility, de red 295-297
Odoo Entornos openerp.Http.Petición 299
Gestor, orden de inicio utilizó 9, 10 openerp.Http.Ruta 297
Odoo maintainers El regreso valora 297, 298
URL 5 pdb
Odoo Bases de datos de URL 164
servidor que dirigen 10, El pivote ve 213-215
11 poedit
Odoo Concha URL 264

374
PO Manipulación de archivo Reglas
URL 266 récord
PostgreSQL Configuración 6, aproxima
7 PostgreSQL sintonía 349, damente
350 campo de prioridad 313 127
Producción Utilizado, para acceso récord limitativo
Configuración, adaptando 351-355 243-246
Odoo, instalando 345-348 Registros
pudb Registros nuevos, creando
URL 164 102-104 búsqueda,
peticiones personalizando 120-123
de atracción buscando 107, 108
Aproximadame
nte 43, 44
aplicando 43,
44
Código de pitón 54
Acciones de Servidor de
código de pitón que
utilizan 281, 282
Depurador de pitón
Utilizado, para localizar ejecución de método
159-163
Pruebas de unidad de la pitón
Utilizado, para escribir el módulo prueba
168-171

Q
QUnit
URL 336
QWeb
Aproximadament
e 314, 315
atributos 316
conditionals 316
campos 316
inline Editando
317 bucles 316
informes 215-
217

R
readonly Propiedad
330 acceso récord
Reglas limitativas , récord utilizaron 243-
245
Listas récord
Filtros, registro 193-195
recordsets RPC Llamadas
Peinando 109, 110 Haciendo, a servidor 333-336
Vacío recordset, consiguiendo para modelo RPC Interfaz
diferente 101, 102 Métodos, escondiendo de 98
Filtrando 110-112
Valores de registros, actualizando S
104-107 relationes, traversing
112-114 scaffold
Campos de referencia Utilizado, para crear módulo 61, 62
Utilizado, para añadir relaciones dinámicas La búsqueda ve 198
86, 87 Seguro_uninstall módulo comunitario
Campos relacionales URL 250
Añadiendo, a modelo 74-77 grupos de
Informe.Diseño_externo 317 seguridad
RequireJS Asignando, a usuarios 233-
URL 313 237 creando 233-237
Calendario de recurso 287 Utilizado, para activar características 246-
ReStructuredText (RST) Formato 251
URL 50 Servidor
Modelo reutilizable features Acciones, creando 273-276
los modelos abstractos que RPC llamadas, haciendo
utilizan 89-91 333-336
Inverso proxy Copia de seguridad de
aproximada bases de datos del
mente 354 servidor, restaurando 16
Configurando 357-362 base de datos,
RPC API respaldando arriba 15
Utilizando 307-309 Base de datos, duplicando 13, 14

375
Interfaz de administración de la creando 314,
base de datos, accediendo 315 campos
10 316
Base de datos,
sacando 14 gestor 10
Contraseña maestra, cambiando
11, 12 contraseña maestra,
encuadre 11
Base de datos nueva, creando
12, 13 laborable 17-19
Registros de servidor
Produciendo, para ayudar depurar métodos
153-156
Lado de servidor
onchange Métodos, llamando 141-
143 pruebas de servidor
Corriendo 172, 173
Fragmento
Ofrenda, a usuario 318-322
Fuente
Odoo, instalando de 2-5
Odoo, actualizando de 25-27
Vista concreta
De apertura, por acción 184, 185
Consultas de SQL
que ejecutan 130-
132
SSL
Configurando 357-362
SSL Certificado
358 orden de inicio
Utilizado, para gestor Odoo entornos 9, 10
Subtipos 279
systemd
Configurando, para empezar Odoo 356
sysvinit
Configurando, para empezar Odoo 356, 357

T
t-Tan atributo 316 t-att-
dateCreated 316 t-attf-
atributo de clase 316 t-
attf-* construcción 316
t-atributo de llamada
315 elemento de
plantilla 318 plantillas

Atributos 316
conditionals 316
inline Editando 317, 318 Configurando, para empezar Odoo 356,
modificando 314, 315 357
Pruebas Usuario
Escritura, para client-código de lado 336-339 Errores, informando 99, 100
escritura para módulo, pruebas de unidad de Actuando acción, cambiando 126,
la Pitón utilizaron 127 preferences, configurando 253-
168-171 256 redirigiendo 137
Escritura para módulo, YAML utilizó 164-166 Fragmento, ofrenda 319-323
t-Atributo de opciones del
campo 316 t-foreach elemento V
316 condiciones de tiempo
Automatizó acciones, utilizando 283-287 Vistas
Modelos transitorios 133 Añadiendo 57-61
archivos de traducción Orden de evaluación 204,
importing 266, 267 205 herencia 201-203
Traducciones Entornos virtuales (virtualenv) 5, 6, 368
Aliviando, gettext las herramientas utilizaron
264-266 W
Cuerdas de traducción
Web acceso de caminos
que exportan 261- accesibles, restringiendo
264 300-302
Ventajas de
U web 54 web
UI módulo
Traduciendo 258-260 URL 339
upstart Sitio web.Plantilla de diseño 315-317

376
werkzeug X
URL 295
widgets XML archivos
Añadiendo, para formar Utilizado, para cargar dato 221-224
vista 186 acción de XMLRPC 309
ventana
Añadiendo 180-183 Y
Brujo
Aproximadamente 91, 133 YAML
Y reutilización de código 136 Archivos, utilizados para cargar dato
Escritura, para guiar usuario 228, 229 utilizó, para escribir el
133-136 módulo prueba 164-167
Wkhtmltopdf
Aproximada
mente 5
URL 5
Definicionesde flujo del trabajo
URL 294
Escribe()
Extendiendo 117-120
377

Das könnte Ihnen auch gefallen