<a id="document-template-basics"></a>
<a id="id1"></a>
# Document Template Basics

A Document Template is simply a text document which contains placeholders for data. When a user generates a document for a Draft or Project using the Document Template the data from that particular Draft or Project is injected into the template.

For example, to insert the name of the Draft into a template we might have a template:

```jinja
Draft Name : {{ draft.DraftName }}
```

When this Template is run against a Draft called "Draft 1" we will get the content:

```
Draft Name : Draft 1
```

The {{ and }} denote the start and end of placeholders and the draft.DraftName within tells the system that we want the value of the DraftName attribute of the draft object.

The *draft* object has many more attributes than *DraftName* (see the [Object Model Reference](attribute_reference.html.md#attribute-reference)). As an example we might want to list all the Forms in the Draft.

> **Note:** The [Object Model Reference](attribute_reference.html.md#attribute-reference) is the complete list of what a template can read. A template which reads an object or an attribute that is not listed there fails with an error naming what it refused, rather than rendering a blank value - so a typo shows up as a clear message instead of a silently missing column.

```jinja
Draft Name : {{ draft.DraftName }}

Forms
=====
{% for form in draft.als_forms_set.all() %}
{{ form.OID }}
{% endfor %}
```

In this example we loop through all the forms defined in the Draft and insert their OIDs into the generated document. If Draft1 contained 3 Forms "FORMA","FORMB" and "FORMC" we would see:

```
Draft Name : Draft1

Forms
=====
FORMA
FORMB
FORMC
```

TrialGrid uses the [Jinja2 template system](https://jinja.palletsprojects.com/). The Document Template examples show usage of the Jinja2 template system but do not provide a tutorial on the syntax itself. The Jinja2 website offers excellent reference material to learn the syntax.

A set of objects such as `draft.als_forms_set` does not have to be read whole. You can choose the objects you want, for example only the active Forms, put them in order, for example by OID, or just count them. [Choosing and Counting Objects](querying_objects.html.md#querying-objects) lists every method you can use, with examples.

[Filters](template_filters.html.md#template-filters) lists every filter a template can use, such as `join`, `format_datetime` and `xml_escape`, with an example of each.

<a id="collecting-values-in-a-loop"></a>
## Collecting values in a loop

A `{% set %}` inside a loop does not change a value set outside it, so a total or a list built that way is still empty after the loop. There are two ways round this.

Add to a list with `{% do %}`, which runs an expression without writing anything:

```jinja
{% set oids = [] %}
{% for form in draft.als_forms_set.order_by("Ordinal") %}
{% do oids.append(form.OID) %}
{% endfor %}
Forms: {{ oids|join(", ") }}
```

Or keep the value in a `namespace`, whose attributes a `{% set %}` inside the loop can change:

```jinja
{% set totals = namespace(fields=0) %}
{% for form in draft.als_forms_set.all() %}
{% set totals.fields = totals.fields + form.als_fields_set.count() %}
{% endfor %}
Fields: {{ totals.fields }}
```

<a id="line-breaks-after-tags"></a>
<a id="template-line-breaks"></a>
## Line breaks after tags

The line break that follows a `{% %}` tag is removed, so that lines holding only a tag, like `{% for %}` and `{% endfor %}`, do not leave blank lines in the document. It also means a line that ends with a tag joins the next one: a line ending `{% endif %}` runs into whatever comes after it.

To choose between words at the end of a line, use an expression instead of `{% if %}`:

```jinja
{% for form in draft.als_forms_set.order_by("Ordinal") %}
{% set count = form.als_fields_set.count() %}
{{ form.OID }}: {{ count }} {{ "field" if count == 1 else "fields" }}
{% endfor %}
```

<a id="template-scope"></a>
### Template Scope

Document templates have a *Scope* which determines where the document template can be accessed and what data it receives.

Templates with a **Draft Home** scope can be accessed from the [Draft Home Page](../../draft_home.html.md#draft-home). They receive a *draft* object which represents the Draft the template is being generated for.

```jinja
Draft Name : {{ draft.DraftName }}

Forms
=====
{% for form in draft.als_forms_set.all() %}
{{ form.OID }}
{% endfor %}
```

Templates with a **Project Home** scope can be accessed from the [Project Home Page](../../project_home.html.md#project-home). They receive a *project* object which represents the Project the template is being generated for.

Example:

```jinja
Project Name : {{ project.ProjectName }}

Drafts
======
{% for draft in project.als_crfdraft_set.all() %}
{{ draft.DraftName }}
{% endfor %}
```

Templates with a **Project Tickets** scope can be accessed from the [Project Tickets Page](../../tickets.html.md#project-tickets). They receive a *project* object which represents the Project the template is being generated for as well as the page of the tickets listing they are being run on (open, closed, all) and any filters or search active:

Example:

```jinja
Project Name : {{ project.ProjectName }}

Ticket Page: {{ ticket_page.title() }}

Active Search: {{ search_text or 'None' }}
Label Filter : {{ " ,".join(filter_labels) or 'None' }}
Assignments Filter : {{ filter_assignments }} {# All, Unassigned, Assigned to me #}

Tickets
=======
{% for ticket in project.ticket_set.filter(id__in=filtered_ids).order_by('iid') %}
{{ticket.iid}} : {{ ticket.title }}
{% endfor %}
```

Templates with a **Draft Object List** scope can be accessed from the "Actions" menu of a Draft object listing — [Forms](../../form_list.html.md#form-list), [Fields](../../field_list.html.md#field-list), [Folders](../../folder_list.html.md#folder-list), [Edit Checks](../../check_list.html.md#check-list), [Derivations](../../derivation_list.html.md#derivation-list), [Custom Functions](../../custom_function_list.html.md#custom-function-list), [Data Dictionaries](../../datadictionary_list.html.md#datadictionary-list), [Unit Dictionaries](../../unitdictionary_list.html.md#unitdictionary-list), [Matrices](../../matrix_list.html.md#matrix-list), [Standard Rules](../../standard_rules.html.md#standard-rules) and [Custom Objects](../../draft_custom_objects_list.html.md#custom-object-list).

A Draft Object List template must say which **Object Type** it reports on. The Object Type is chosen next to the Scope when editing the Template, and the Template is then offered only on that Object Type's listing — a report for Forms does not appear on the Fields list.

These templates receive a *draft* object, the objects the user had selected with the row checkboxes, the objects matching whatever search and filters were active, and — in *all_objects* — every object of the Template's Object Type in the Draft:

Example:

```jinja
{{ object_type_plural }} in {{ draft.DraftName }}

Active Search: {{ search_text or 'None' }}

Selected
========
{% for form in selected_objects %}
{{ form.OID }} : {{ form.DraftFormName }}
{% endfor %}
```

Because the Template is tied to one Object Type, *selected_objects* and *filtered_objects* already contain only objects of that type. See [Draft Object List Template Context](template_context_draft_object_list.html.md#template-context-draft-object-list) for the full list of values these Templates receive.

> **Note:** Generating with no rows selected is a normal way to use these Templates. *selected_ids* and *selected_objects* are then empty while *filtered_ids* and *filtered_objects* hold everything currently listed, so a Template written against *filtered_objects* reports on whatever the user is looking at. *all_objects* is unaffected by either, so a Template can list the whole set and mark the rows the user picked out.

<a id="turning-text-content-into-other-formats-word-pdf-excel-etc"></a>
### Turning Text Content into other Formats (Word, PDF, Excel etc)

Templates that are set to be of type "Word" must have content that conforms to the TrialGrid Ltd *DocXMarkup* format. The template text is generated and the resulting expanded text is then processed again by DocXMarkup into a Word format document which can be downloaded by the user. See the section on [Generating Word Documents](generating_word_documents.html.md#generating-word-documents) for more information.

Templates that are set to be of type "PDF" must have content that conforms to the *ReportLab Markup* (RML) format. Similarly to the Word process, generating of PDF output is a two-step process that first expands the text template and then takes the expanded template and processes it to produce PDF output. See the section on [Generating PDF Documents](generating_pdf_documents.html.md#generating-pdf-documents) for more information.

Templates that are set to be of type "Excel 2003/2004" must have content that conforms to the Microsoft Excel 2003/2004 format. See the section on [Generating Excel Documents](generating_excel_documents.html.md#generating-excel-documents) for more information.

Plain text templates can be useful for generating output for system integration. Text format templates can be used to generate tab-delimited or Comma-separated values files and XML files.

Values are escaped in a Text template just as in the other types (see [Values are escaped](template_filters.html.md#template-filters-escaping)). That suits XML, but output that is not markup, such as plain text, Markdown or CSV, wants each value exactly as it is stored, so write it with `|safe`. Without it a quote in a value comes out as `&#34;`, and escaping it again with `xml_escape` gives `&amp;#34;`.

This template writes a Draft's Test Cases as Markdown, ready to give to an AI or another tool. Each Test Case is a heading followed by its Gherkin in a fenced block, so that a `#` comment or a `|` table in the Gherkin is not read as Markdown. Template Test Cases, which other Test Cases include, are left out:

`````jinja
# Test Cases in {{ draft.DraftName|safe }}

{% for tc in draft.testcase_set.filter(is_template=False).order_by("name") %}
## {{ tc.name|safe }}

ID: {{ tc.id }}

````gherkin
{{ tc.content|safe }}
````

{% endfor %}
`````

Templates that are set to be of type "AI Summary" use a two-stage process: the template is first expanded to produce a plain text prompt which is then sent to an AI language model for summarization. The AI response is saved as a text file. See the section on [Generating AI Summaries](generating_ai_summaries.html.md#generating-ai-summaries) for more information.

<a id="security-and-performance"></a>
### Security and Performance

The `draft` object is the entrypoint into the TrialGrid object model. From a Draft you can move up the hierarchy into the [Project](attribute_reference.html.md#attribute-project) and from the Project up to the [URL](attribute_reference.html.md#attribute-url). However, you cannot use this system to investigate other Projects or URL's.

In addition, generating documents may cause a lot of database queries. In order to limit the performance impact of users running very large document generation tasks (hundreds or thousands of pages) a time limit is enforced on how long a report can run.

<a id="setting-the-name-of-the-generated-file"></a>
### Setting the name of the generated file

By default the name of the file generated is the same as the name of the Document Template with spaces and characters that are not allowed in file names replaced with underscores (_). It is sometimes convenient to change the name of the generated document to include the name of the Draft or some other value. This can be achieved by setting the name inside the template with `{% do SET_FILE_NAME(..) %}` The value of the file name can also be retrieved using `{{ GET_FILE_NAME() }}`

For example, if the name of the Draft is "Draft 1" then:

```jinja
{% do SET_FILE_NAME(draft.DraftName + ' Test') %}
{{ GET_FILE_NAME() }}
```

returns:

```
Draft_1_Test
```
