Digests

This document describes all the data available in Jinja2 templates for email digests.

Table of Contents

Main Context Variables

The following top-level variables are always available in your templates:

Variable Type Description
digest    object The digest configuration and metadata
equipment    object Equipment calibration data
qualifications    object Staff qualifications data
quotes    object Project quotes and enquiries data
leave    object Leave/vacation data
today    date Current date
user    object Current user (only in individual mode)

Digest Information

digest    object

Contains the digest configuration:

Field Type Description
id    integer Unique identifier
name    string Name of the digest
org    object Organization (see below)
individual    boolean Whether individual emails are sent
subject    string Email subject template
equipment_days_before    integer Days before today for equipment data
equipment_days_after    integer Days after today for equipment data
qualifications_days_before    integer Days before today for qualifications
qualifications_days_after    integer Days after today for qualifications
leave_days_before    integer Days before today for leave data
leave_days_after    integer Days after today for leave data
created    datetime Creation timestamp
created_by    object User who created (see User object)
modified    datetime Last modification timestamp
modified_by    object User who modified (see User object)

digest.org    object

Field Type Description
id    integer Organization ID
name    string Organization name

Equipment Data

equipment    object

Contains two arrays of equipment items:

Field Type Description
expired    array Equipment with expired calibration
expiring    array Equipment with upcoming calibration

Equipment Item Structure

Each item in equipment.expired    or equipment.expiring   :

Field Type Description
id    integer Equipment ID
name    string Equipment name
category    object Equipment category (id, name)
serial    string Serial number
calibration    date Calibration due date
identifier    string Equipment identifier
barcode    string Barcode value

Example Usage

{% if equipment.expired %}
<h3>Expired Equipment</h3>
<ul>
{% for item in equipment.expired %}
  <li>{{ item.name }} - Expired on {{ item.calibration }}</li>
{% endfor %}
</ul>
{% endif %}

{% if equipment.expiring %}
<h3>Equipment Due for Calibration</h3>
<ul>
{% for item in equipment.expiring %}
  <li>{{ item.name }} - Due {{ item.calibration }}</li>
{% endfor %}
</ul>
{% endif %}

Qualifications Data

qualifications    object

Contains two arrays of qualification items:

Field Type Description
expired    array Expired qualifications
expiring    array Qualifications expiring soon

Qualification Item Structure

Each item in qualifications.expired    or qualifications.expiring   :

Field Type Description
id    integer Qualification ID
user    object User with qualification (see User object)
name    string Qualification name
reference    string Reference number
start    date Start date
end    date Expiry date

Example Usage

{% if qualifications.expiring %}
<h3>Qualifications Expiring Soon</h3>
<table>
  <tr><th>Employee</th><th>Qualification</th><th>Expires</th></tr>
{% for qual in qualifications.expiring %}
  <tr>
    <td>{{ qual.user.name }}</td>
    <td>{{ qual.name }}</td>
    <td>{{ qual.end }}</td>
  </tr>
{% endfor %}
</table>
{% endif %}

Quotes Data

quotes    object

Contains two arrays of project/quote items:

Field Type Description
created    array Enquiries (not yet quoted)
open    array Open quotes (quoted but not decided)

Quote Item Structure

Each item in quotes.created    or quotes.open   :

Field Type Description
id    integer Project ID
name    string Project name
reference    string Project reference
client    object Client (id, name)
category    object Project category (id, name)
created    datetime Creation date
created_by    object User who created (id, name)
modified    datetime Last modification date
modified_by    object User who modified (id, name)
quoted    date Date quoted (null for enquiries)
quoted_by    object User who quoted (id, name)
price_net    decimal Net price
currency    string Currency code
deadline    date Project deadline
quote_deadline    date Quote validity deadline
quote_decision    string Quote decision status

Example Usage

{% if quotes.created %}
<h3>New Enquiries</h3>
<ul>
{% for quote in quotes.created %}
  <li>
    <strong>{{ quote.client.name }}</strong>: {{ quote.name }}
    (Created {{ quote.created|date:"Y-m-d" }})
  </li>
{% endfor %}
</ul>
{% endif %}

{% if quotes.open %}
<h3>Quotes Awaiting Decision</h3>
<ul>
{% for quote in quotes.open %}
  <li>
    {{ quote.client.name }}: {{ quote.name }} 
    - Quoted {{ quote.quoted|date:"Y-m-d" }}
    {% if quote.quote_deadline %} (Valid until {{ quote.quote_deadline }}){% endif %}
  </li>
{% endfor %}
</ul>
{% endif %}

Leave Data

leave    object

Contains two arrays of leave items:

Field Type Description
created    array Leave requests pending approval
approved    array Approved leave in date range

Leave Item Structure

Each item in leave.created    or leave.approved   :

Field Type Description
id    integer Leave ID
user    object Employee (see User object)
type    object Leave type (id, name)
start    date Start date
end    date End date
days    decimal Number of days
hours    decimal Number of hours
decision    string Decision status (empty="Requested", "A"="Approved", "D"="Denied")
decided    datetime When decision was made
decided_by    object Manager who decided (see User object)
decided_notes    string Decision notes

Example Usage

{% if leave.created %}
<h3>Pending Leave Requests</h3>
<ul>
{% for request in leave.created %}
  <li>
    {{ request.user.name }} - {{ request.type.name }}
    ({{ request.start }} to {{ request.end }}, {{ request.days }} days)
  </li>
{% endfor %}
</ul>
{% endif %}

{% if leave.approved %}
<h3>Upcoming Leave</h3>
<ul>
{% for absence in leave.approved %}
  <li>
    {{ absence.user.name }}: {{ absence.start|date:"M d" }} - {{ absence.end|date:"M d" }}
  </li>
{% endfor %}
</ul>
{% endif %}

User Object Structure

User objects appear in various places and have this structure:

Field Type Description
id    integer User ID
name    string Full name
email    string Email address
first_name    string First name
last_name    string Last name

Individual Mode

When digest.individual    is true   , each recipient gets a personalized email with an additional user    variable:

user    object (only in individual mode)

The full user object for the recipient, containing all user profile data.

Example Usage

{% if user %}
  <p>Hello {{ user.first_name }},</p>
  <p>Here's your personal digest for {{ today|date:"F j, Y" }}:</p>
{% else %}
  <p>Team Digest for {{ today|date:"F j, Y" }}:</p>
{% endif %}

Conditional Display

Use Jinja2 conditionals to show/hide sections:

{% if equipment.expired or equipment.expiring %}
<section class="equipment-section">
  <!-- Equipment content -->
</section>
{% endif %}

{% if leave.created|length > 5 %}
<p class="alert">{{ leave.created|length }} leave requests pending!</p>
{% endif %}

Loops and Filters

Common Jinja2 filters useful for digests:

{{ items|length }}                 <!-- Count items -->
{{ price|floatformat:2 }}          <!-- Format decimal -->
{{ text|truncatewords:20 }}        <!-- Limit text length -->
{{ value|default:"N/A" }}          <!-- Default value -->

{% for item in items|slice:":5" %} <!-- First 5 items -->
  <!-- ... -->
{% endfor %}

Complete Example Template

<!DOCTYPE html>
<html>
<head>
    <title>{{ digest.org.name }} Digest - {{ today|date:"F j, Y" }}</title>
</head>
<body>
    <h1>{{ digest.org.name }} Weekly Digest</h1>
    <p>Report generated on {{ today|date:"l, F j, Y" }}</p>

    {% if quotes.created or quotes.open %}
    <h2>Projects & Quotes</h2>
    
    {% if quotes.created %}
    <h3>New Enquiries ({{ quotes.created|length }})</h3>
    <ul>
    {% for project in quotes.created|slice:":10" %}
        <li>{{ project.client.name }}: {{ project.name }}</li>
    {% endfor %}
    </ul>
    {% endif %}
    
    {% if quotes.open %}
    <h3>Quotes Pending Decision ({{ quotes.open|length }})</h3>
    <ul>
    {% for project in quotes.open %}
        <li>
            {{ project.client.name }}: {{ project.name }}
            - {{ project.currency }} {{ project.price_net|floatformat:2 }}
            {% if project.quote_deadline %}
            (Expires: {{ project.quote_deadline|date:"M d" }})
            {% endif %}
        </li>
    {% endfor %}
    </ul>
    {% endif %}
    {% endif %}

    {% if leave.created or leave.approved %}
    <h2>Leave Management</h2>
    
    {% if leave.created %}
    <h3>Pending Approvals</h3>
    <table>
    {% for request in leave.created %}
        <tr>
            <td>{{ request.user.name }}</td>
            <td>{{ request.start|date:"M d" }} - {{ request.end|date:"M d" }}</td>
            <td>{{ request.days }} days</td>
        </tr>
    {% endfor %}
    </table>
    {% endif %}
    {% endif %}

    {% if equipment.expired %}
    <h2>⚠️ Expired Equipment Calibrations</h2>
    <ul>
    {% for item in equipment.expired %}
        <li>{{ item.name }} ({{ item.category.name }}) - Expired {{ item.calibration }}</li>
    {% endfor %}
    </ul>
    {% endif %}

    {% if user %}
    <hr>
    <p><small>This digest was personalized for {{ user.name }}.</small></p>
    {% endif %}
</body>
</html>

Notes for Template Designers

  1. Always check for data existence before displaying sections to avoid empty headers
  2. Use the |length    filter to show counts in section headers
  3. Consider using |slice    to limit long lists in summary views
  4. Format dates consistently throughout the template
  5. Test with both individual and non-individual modes if your digest supports both
  6. Remember that user    is only available in individual mode
  7. All date/datetime fields can be null - always check before displaying

Testing Your Templates

To test your templates with sample data:

  1. Create a test digest in the admin panel
  2. Set appropriate day ranges for each data type
  3. Send test emails to verify formatting
  4. Test both with and without data in each section
  5. Test individual mode if applicable
Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.

Still need help? Contact Us Contact Us