> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Motor de plantillas de Reporter

> Cómo evalúa Reporter una plantilla: el mapa de campos que deriva, el contexto de datos que construye, los bloques, los filtros de plantilla, los filtros de fila y el modelo de fuentes de datos multiesquema.

Una plantilla de Reporter es un archivo de texto plano `.tpl`. Reporter la renderiza con un motor Pongo2, que interpreta etiquetas al estilo Django y filtros con sintaxis de barra vertical.

[Referencia de plantillas](/es/products/reporter/template-reference) enumera cada etiqueta y filtro. [Formatos de plantilla](/es/products/reporter/template-examples) muestra un archivo resuelto por cada formato de salida.

## El mapa de campos

***

Cuando subes una plantilla, Reporter analiza el texto y deriva un **mapa de campos**: cada fuente de datos, cada tabla y cada campo que la plantilla nombra.

```json theme={null}
{
  "external_db": {
    "sales__orders": ["id", "total", "created_at"]
  }
}
```

El mapa se almacena junto con los metadatos de la plantilla y viaja con cada solicitud de informe. La extracción lee solo lo que el mapa lista. Un campo que tu plantilla nunca nombra nunca se consulta, así que una plantilla se mantiene económica a medida que crecen las tablas subyacentes.

De esto se derivan dos consecuencias. Primero, Reporter deriva el mapa cuando subes o reemplazas el archivo, nunca en el momento del renderizado. Una nueva referencia de campo llega a un informe solo después de que subes la plantilla modificada.

Segundo, Reporter verifica el mapa contra el esquema en vivo de cada fuente de datos en el momento de la carga. Un nombre de tabla incorrecto o un nombre de campo incorrecto aparece ahí, antes de que se ejecute cualquier informe. Cuando una fuente de datos no puede responder, Reporter devuelve advertencias y aun así acepta la plantilla. Una base de datos inalcanzable no bloquea tu trabajo.

## El contexto de datos

***

La extracción construye un único contexto para el renderizado. El primer nivel es el nombre de configuración de la fuente de datos. El segundo nivel es la tabla. Cada valor es una lista de filas.

```json theme={null}
{
  "external_db": {
    "orders": [
      { "id": "018f...", "total": "1200.00", "created_at": "2026-07-01" }
    ]
  }
}
```

Tu plantilla se refiere a ese contexto con los mismos nombres que usó para declararlos:

```django theme={null}
{% for order in external_db.orders %}
  {{ order.id }} — {{ order.total|floatformat:2 }}
{% endfor %}
```

Las filas regresan bajo la clave que escribió tu plantilla. Un nombre de tabla sin calificar permanece sin calificar. Una referencia calificada por esquema se convierte en `schema__table`, con doble guion bajo, tanto en el mapa de campos como en el contexto de renderizado. Los filtros de fila son más flexibles y aceptan tanto `schema.table` como `schema__table`.

### Variables

Una plantilla lee el contexto a través de variables. Un alias de bucle vincula una fila a la vez, y `{% with %}` nombra parte del contexto para el bloque que le sigue. Ambos alias son locales al bloque que los declara.

El analizador rastrea un alias hasta la tabla que hay detrás de él. Un campo que lees como `order.total` dentro de un bucle sobre `external_db.orders` llega al mapa de campos como `total` bajo esa tabla, así que la extracción lo devuelve.

## Fuentes de datos multiesquema

***

Una fuente de datos normalmente vive en el registro persistente de Reporter y se gestiona a través de la [API de fuentes de datos](/es/reference/products/reporter/list-data-sources). En modo de un solo tenant, un bloque de entorno puede sembrar una entrada del registro al iniciar el Manager, solo cuando ninguna entrada activa o eliminada de forma lógica ya usa ese nombre de configuración. El modo multi-tenant crea fuentes de datos por tenant a través de la API. `CONFIG_NAME` establece el nombre que usan tus plantillas, y `SCHEMAS` lista los esquemas que Reporter descubre en ella. Usa el mismo nombre para el segmento de nombre de entorno y para `CONFIG_NAME`, en mayúsculas en las claves de las variables de entorno, como en el bloque de abajo:

```bash theme={null}
DATASOURCE_EXTERNAL_DB_CONFIG_NAME=external_db
DATASOURCE_EXTERNAL_DB_HOST=external-postgres
DATASOURCE_EXTERNAL_DB_PORT=5432
DATASOURCE_EXTERNAL_DB_USER=db_user
DATASOURCE_EXTERNAL_DB_DATABASE=external_database
DATASOURCE_EXTERNAL_DB_TYPE=postgresql
DATASOURCE_EXTERNAL_DB_SCHEMAS=sales,inventory,reporting
```

Sin `SCHEMAS`, Reporter descubre solo el esquema `public`. La clave del esquema es `DATASOURCE_{CONFIG_NAME}_SCHEMAS`, mientras que las demás claves de entorno usan el segmento `{NAME}`. Consulta [Variables de entorno](/es/products/reporter/reporter-environment-variables) para ver el bloque de arranque completo.

El motor resuelve un nombre de tabla sin calificar contra cada esquema descubierto:

| Propietarios del nombre de la tabla        | Resultado                                                       |
| ------------------------------------------ | --------------------------------------------------------------- |
| Exactamente un esquema                     | El motor lee esa tabla.                                         |
| Varios esquemas, uno de ellos `public`     | El motor lee la tabla de `public`.                              |
| Varios esquemas, ninguno de ellos `public` | El motor reporta la tabla como ambigua y nombra los candidatos. |
| Ningún esquema                             | El motor reporta la tabla como no encontrada.                   |

Califica la referencia para eliminar la ambigüedad. La forma calificada nombra la fuente, el esquema y la tabla:

```django theme={null}
{% for order in external_db:sales.orders %}
  {{ order.id }}
{% endfor %}
```

Una referencia calificada debe coincidir exactamente con el esquema descubierto. El motor no la busca en otros esquemas.

## Bloques

***

Un bloque es la unidad con la que trabaja el generador visual de plantillas. Existen trece tipos, en seis categorías:

| Categoría             | Tipos de bloque                                         |
| --------------------- | ------------------------------------------------------- |
| Básica (`basic`)      | `text`, `variable`, `comment`                           |
| Control (`control`)   | `loop`, `conditional`, `with`                           |
| Datos (`data`)        | `aggregation`, `calculation`, `date_time`, `expression` |
| Diseño (`layout`)     | `section`                                               |
| Numeración (`dimp`)   | `counter`                                               |
| Avanzada (`advanced`) | `custom_tag`                                            |

El valor entre paréntesis es lo que el catálogo de bloques devuelve como la cadena de categoría. Un cliente que compara la respuesta de la API se basa en eso, no en la etiqueta.

Cuatro de ellos contienen hijos: `loop`, `conditional`, `section` y `with`. Un conditional también lleva ramas alternativas. Los bloques se anidan hasta cincuenta niveles de profundidad.

Los bloques nunca se almacenan. El generador los envía a Reporter, y Reporter devuelve el código fuente Pongo2 más el mapa de campos que ese código implica. La plantilla que subes siempre es el texto.

Tres operaciones dan soporte a ese flujo:

* [Validar bloques de plantilla](/es/reference/products/reporter/validate-template-blocks) verifica la estructura, analiza el código generado y reporta cada problema contra el bloque que lo causó.
* [Generar código de plantilla](/es/reference/products/reporter/generate-template-code) devuelve el código final para un formato de salida.
* [Listar definiciones de bloque](/es/reference/products/reporter/list-block-definitions) devuelve el catálogo, para que un cliente se mantenga sincronizado con el motor.

## Dos tipos de filtro

***

Reporter usa la palabra filtro para dos cosas distintas, y se ejecutan en momentos diferentes.

**Los filtros de fila** se ejecutan durante la extracción. Viven en la solicitud del informe, no en la plantilla, y limitan las filas que devuelve la base de datos. El payload los anida en tres niveles: fuente de datos, luego tabla, luego campo.

```json theme={null}
{
  "templateId": "018f2a6c-1c2f-7a10-9f1e-2b8c4d5e6f70",
  "filters": {
    "external_db": {
      "orders": {
        "status": { "nin": ["cancelled", "draft"] },
        "created_at": { "gte": ["2026-07-01"], "lte": ["2026-07-31"] }
      }
    }
  }
}
```

Existen ocho operadores:

| Operador  | Significado                          | Valores         |
| --------- | ------------------------------------ | --------------- |
| `eq`      | Coincide con cualquier valor listado | Uno o más       |
| `gt`      | Por encima del valor                 | Uno             |
| `gte`     | En o por encima del valor            | Uno             |
| `lt`      | Por debajo del valor                 | Uno             |
| `lte`     | En o por debajo del valor            | Uno             |
| `between` | Dentro de un rango inclusivo         | Exactamente dos |
| `in`      | Coincide con cualquier valor listado | Uno o más       |
| `nin`     | Excluye todos los valores listados   | Uno o más       |

Cada operador toma un arreglo. Varios operadores sobre un mismo campo se combinan, como muestra el rango de fechas anterior.

**Los filtros de plantilla** se ejecutan durante el renderizado, después de que llegan las filas. Dan forma a un valor dentro del documento, y usan sintaxis de barra vertical: `{{ value|percent_of:total }}`. [Listar definiciones de filtro](/es/reference/products/reporter/list-filter-definitions) devuelve el catálogo con un ejemplo por filtro.

## El paso de renderizado

***

El motor analiza la plantilla preparada una vez por informe y la ejecuta contra el contexto. Dos comportamientos de ese paso cambian cómo diseñas un documento.

La salida numérica pierde sus ceros finales, así que `1200.00` se renderiza como `1200`. Usa `floatformat` cuando una columna necesite decimales fijos. Los valores que llevan varios puntos permanecen intactos, lo que mantiene sin cambios un código contable como `1.1.2.00.000`.

Una plantilla XML puede declarar la codificación del archivo almacenado. Coloca el marcador en la misma línea que la declaración XML:

```django theme={null}
{# reporter:output-encoding=utf-16be #}<?xml version="1.0" encoding="UTF-16"?>
```

Reporter entonces escribe el archivo en UTF-16BE sin marca de orden de bytes. La salida en PDF ignora el marcador.

## Límites que aplica el motor

***

<Note>
  Reporter bloquea las etiquetas de Pongo2 que cargan o extienden otro archivo: `include`, `extends`, `import`, `block` y `ssi`. Una plantilla es un documento autocontenido.
</Note>

El anidamiento de bloques se detiene en cincuenta niveles, tanto en la validación como en la generación de código. Los campos de bloque de forma libre rechazan los delimitadores de plantilla, de modo que la entrada del generador no puede inyectar una etiqueta. Las plantillas subidas rechazan las etiquetas de script.

## Próximos pasos

***

<CardGroup cols={2}>
  <Card title="Cómo funciona la generación de informes" icon="diagram-project" href="/es/products/reporter/how-report-generation-works">
    El camino desde una solicitud de informe hasta un archivo que puedes descargar.
  </Card>

  <Card title="Referencia de plantillas" icon="code" href="/es/products/reporter/template-reference">
    Cada etiqueta, filtro y operador que acepta la sintaxis.
  </Card>

  <Card title="Formatos de plantilla" icon="file-lines" href="/es/products/reporter/template-examples">
    Una plantilla resuelta por cada formato de salida.
  </Card>

  <Card title="Conceptos básicos de Reporter" icon="cubes" href="/es/products/reporter/reporter-core-concepts">
    Plantillas, fuentes de datos, informes y plazos en un solo lugar.
  </Card>
</CardGroup>
