Ir al contenido

Website y eCommerce: extender plantillas sin romper el tema

theme.ir.ui.view, snippets y páginas dinámicas
26 de junio de 2026 por
Website y eCommerce: extender plantillas sin romper el tema
Atemi, Aitor Atencia

Odoo · Website · eCommerce

Personalizar el website de Odoo sin romper el tema es cuestión de herencia, no de reescritura. Editar plantillas con replace agresivo, mezclar cambios de tema con datos de la web o tocar vistas del core son las tres vías rápidas a un sitio que se rompe en cada actualización. Veamos cómo extender bien.

Logo Odoo Website
El tema vive en theme.* ; tus cambios funcionales, en vistas heredadas del módulo.

Conceptos

Tema vs módulo: qué va dónde

Necesitas…Lócalo en…
Colores, fuentes, layout baseMódulo tema (theme_*) con theme.ir.ui.view
Bloque reutilizable arrastrableSnippet (plantilla + opciones)
Cambio funcional en una páginaVista heredada en tu módulo de negocio
Página nueva con datos del ORMControlador + plantilla QWeb

Regla de oro: nunca edites una vista del core directamente. Hereda con inherit_id y xpath puntuales.

Herencia

Extender una plantilla del website

<template id="product_extra_info"
          inherit_id="website_sale.product"
          name="Producto: ficha técnica">
    <xpath expr="//div[@id='product_details']" position="inside">
        <div t-if="product.datasheet_url" class="mt-3">
            <a t-att-href="product.datasheet_url"
               class="btn btn-outline-secondary">
                Descargar ficha técnica
            </a>
        </div>
    </xpath>
</template>

Snippets

Un snippet arrastrable

<!-- Plantilla del snippet -->
<template id="s_cta_diagnostic" name="CTA Diagnóstico">
    <section class="s_cta_diagnostic py-5 text-center">
        <h2>¿Reservar una cita?</h2>
        <a href="/contactus" class="btn btn-primary">Contactar</a>
    </section>
</template>

<!-- Registro en el panel de bloques -->
<template id="snippet_cta_register"
          inherit_id="website.snippets">
    <xpath expr="//snippets[@id='snippet_structure']" position="inside">
        <t t-snippet="mi_modulo.s_cta_diagnostic"
           t-thumbnail="/mi_modulo/static/img/cta.svg"/>
    </xpath>
</template>

El class del section (s_cta_diagnostic) identifica el snippet para sus opciones y para el editor. Mantenlo único por módulo.

Páginas dinámicas

Controlador + QWeb con datos del ORM

from odoo import http
from odoo.http import request

class DiagnosticWebsite(http.Controller):

    @http.route('/diagnosticos', type='http', auth='public',
                website=True, sitemap=True)
    def diagnostic_list(self, **kw):
        tests = request.env['diagnostic.test'].sudo().search(
            [('website_published', '=', True)], limit=20)
        return request.render('mi_modulo.page_diagnostics', {
            'tests': tests,
        })

Buenas prácticas

Qué evitar para no romper actualizaciones

❌ Evitar✅ Preferir
position="replace" de bloques grandesinside / after puntuales
Editar vistas del core en la BDVista heredada en tu módulo
CSS inline en cada plantillaSCSS en el bundle web.assets_frontend
Mezclar tema y lógica de negocioTema en theme_*, funcional aparte

Resumen

Separa el tema (apariencia) de tu módulo (funcionalidad). Hereda plantillas con xpath puntuales, registra snippets reutilizables y sirve páginas dinámicas con controladores website=True filtrando siempre los datos públicos. Así sobrevives a cada -u website sin sorpresas.

en Odoo
QWeb para informes PDF: t-out, tablas y cabeceras
Plantilla mínima, paperformat y wkhtmltopdf en Docker