Help

Template Data Guide

Jump to section

Overview

The CalcTemplate Engine renders calculation reports from database-stored templates. Each template defines variables, sections, and equations. The engine evaluates SymPy expressions, substitutes values into LaTeX, and renders a formatted multi-section calculation document.

Rather than writing a separate management command per component, each component opts in by adding a template_data.py file. A single generic command (seed_calc_templates) discovers and seeds all of them.

Why use the template engine? It standardises the output format, enables PDF/Excel export, and lets non-developers edit calculation content via the Engine Admin UI without touching Python code.

Quick Start

To add template data for a new component (e.g. c0042_my_calc):

  1. Create components/c0042_my_calc/template_data.py with the four required exports: TEMPLATE_META, VARIABLES, SECTIONS, EQUATIONS.
  2. Run python manage.py seed_calc_templates my_calc_slug --force to seed (or re-seed) to the database.
  3. Verify in the Engine Admin or by loading the calculation in the UI.
Minimal template_data.py skeleton:
TEMPLATE_META = {
    "name": "My Calculation",
    "slug": "my_calc_slug",
    "description": "Short description of what this calculates",
}

VARIABLES = [
    {"ordering": 0, "name": "V", "symbol": "V", "label": "Voltage", "unit": "V", "is_input": True},
    {"ordering": 1, "name": "I", "symbol": "I", "label": "Current", "unit": "A", "is_input": False},
]

SECTIONS = [
    {"ordering": 0, "slug": "inputs_title", "title": "Input Parameters", "section_type": "title",
     "text_content": "Design parameters:"},
    {"ordering": 1, "slug": "inputs_table", "title": "Input Parameters", "section_type": "table",
     "rows": [("V", "System voltage")]},
    {"ordering": 2, "slug": "calc_section", "title": "Calculation", "section_type": "equations"},
]

EQUATIONS = [
    (2, 0, "Current Calculation", "I", "P / V",
     r"$$ I = \frac{P}{V} $$",
     "$$ I = \\frac{P}{V} = \\frac{.P}{.V} = .I \\; \\text{A} $$",
     "Ohm's law applied to find current."),
]

Data Format Reference

TEMPLATE_META

KeyTypeDescription
namestrHuman-readable template name
slugstrUnique slug (used as DB key and CLI filter)
descriptionstrShort description

VARIABLES

List of dicts, one per variable. All variables must be defined before they can be referenced by sections or equations.

KeyTypeDescription
orderingintDisplay order (0-based)
namestrPython-safe variable name (used in expressions)
symbolstrHTML symbol for display (e.g. V<sub>L-L</sub>)
labelstrHuman-readable label
unitstrUnit string (e.g. "V", "A", "kW"). Blank for dimensionless.
is_inputboolTrue for user inputs, False for calculated outputs

SECTIONS

List of dicts defining the document structure. Sections are rendered in ordering order.

KeyTypeDescription
orderingintRender order (0-based). Also used to link equations.
slugstrUnique slug within template
titlestrSection heading
section_typestrOne of: title, table, equations, svg_display, text
text_contentstr(Optional) Body text for title and text sections
rowslist(Optional) For table sections: list of (variable_name, notes) tuples

EQUATIONS

List of tuples with 8 positional elements:

#NameTypeDescription
0section_orderingintLinks to the ordering of an equations-type section
1equation_orderingintOrder within the section (0-based)
2titlestrEquation heading
3output_variablestrName of the variable this equation solves for
4expressionstrSymPy expression string
5latexstrLaTeX formula (static, no values substituted)
6substitution_latexstrLaTeX with .variable_name placeholders for substitution
7notesstrExplanatory text shown above/below the equation

SymPy Expression Guide

The expression field is evaluated using SymPy's sympify(). Use standard mathematical notation:

OperationExpressionExample
Square rootsqrt(x)sqrt(3) * V * I
Powerx**nI**2 * R
Pipiacos(PF) * 180 / pi
Trigsin(x), cos(x), tan(x)cos(theta)
Inverse trigasin(x), acos(x), atan(x)acos(PF)
Logarithmlog(x) (natural), log(x, 10)20 * log(V1/V2, 10)
Absolute valueAbs(x)Abs(V1 - V2)
Variable names must be valid Python identifiers. Use underscores for subscripts: V_L_L not V(L-L). The display symbol (symbol field) handles the pretty rendering.

LaTeX Guide

Static LaTeX (latex field)

Standard LaTeX wrapped in $$ ... $$ for display math. This is shown as the "formula" line — no values, just the symbolic equation.

Substitution LaTeX (substitution_latex field)

Same structure but with .variable_name placeholders that get replaced with computed values at render time.

Convention: A dot prefix (.) marks a placeholder.
# Static:
r"$$ I = \frac{S}{\sqrt{3} \times V} $$"

# Substitution (note the dot-prefixed variable names):
"$$ I = \\frac{S}{\\sqrt{3} \\times V}"
"\n     = \\frac{.S}{\\sqrt{3} \\times .V_L_L}"
"\n     = .I \\; \\text{A} $$"
Multi-line substitution: Use Python string concatenation with \n to break across lines. Each line shows one step of the substitution (formula → values → result).

Section Types

TypePurposeRequired Fields
title Section heading with optional body text text_content (optional)
table Variable table (shows symbol, value, unit, notes) rows: list of (var_name, notes) tuples
equations Equation block — renders all CalcEquations linked to this section's ordering None (equations link via section_ordering)
svg_display Embedded SVG diagram placeholder SVG content provided at runtime
text Freeform text block (supports HTML) text_content
Ordering matters: Equations reference sections by ordering number. If section ordering 3 is an equations section, then equation tuples with section_ordering=3 will render inside it.

Management Command Reference

# List all discoverable template_data.py modules
python manage.py seed_calc_templates --list

# Seed all templates (skip existing)
python manage.py seed_calc_templates

# Seed all templates (delete and rebuild existing)
python manage.py seed_calc_templates --force

# Seed one specific template by slug
python manage.py seed_calc_templates three_phase_power

# Preview what would be seeded without DB changes
python manage.py seed_calc_templates --dry-run

# Combine: force re-seed a specific template
python manage.py seed_calc_templates three_phase_power --force
FlagDescription
slugs (positional)One or more slugs to filter. Omit for all.
--forceDelete existing templates before re-seeding
--listList discoverable modules and exit
--dry-runPrint what would be seeded without writing to DB

Worked Example

The c0001_vip_3_phase component is the reference implementation. Here is a walkthrough of its template_data.py:

1. Template Meta

TEMPLATE_META = {
    "name": "Three Phase Power",
    "slug": "three_phase_power",
    "description": "Three-phase V-I-P calculator (IEC)",
}

2. Variables

Define all inputs and outputs. The name field is what you use in expressions and table row references.

VARIABLES = [
    {"ordering": 0, "name": "V_L_L", "symbol": "V<sub>L-L</sub>",
     "label": "Voltage (Phase to Phase)", "unit": "V", "is_input": True},
    {"ordering": 1, "name": "I", "symbol": "I<sub>p</sub>",
     "label": "Current (Phase)", "unit": "A", "is_input": True},
    # ... more variables
]

3. Sections

Structure the document: title → input table → title → equations → summary table.

SECTIONS = [
    {"ordering": 0, "slug": "input_parameters_title",
     "title": "Input Parameters", "section_type": "title",
     "text_content": "The following design parameters were considered:"},

    {"ordering": 1, "slug": "input_parameters_table",
     "title": "Input Parameters", "section_type": "table",
     "rows": [("V_L_L", "3-Phase System"), ("I", "Phase Current")]},

    {"ordering": 2, "slug": "calculations_title",
     "title": "Calculations", "section_type": "title"},

    {"ordering": 3, "slug": "current_equation",
     "title": "Current Calculation", "section_type": "equations"},
    # ... more equation sections (one per equation or group)
]

4. Equations

Each equation tuple links to a section by its ordering:

EQUATIONS = [
    (3, 0,                                    # section_ordering=3, equation_ordering=0
     "Current Calculation", "I",              # title, output variable
     "S / (sqrt(3) * V_L_L)",                # SymPy expression
     r"$$ I = \frac{S}{\sqrt{3} \times V} $$",  # static LaTeX
     "$$ I = \\frac{.S}{\\sqrt{3} \\times .V_L_L} = .I \\; \\text{A} $$",  # substitution
     "Full-load current from apparent power"),  # notes
]

Troubleshooting

ErrorCauseFix
Template 'slug' already exists Template was previously seeded Use --force flag to re-seed
row references unknown variable 'X' A table section row references a variable name not in VARIABLES Check spelling of variable name in the rows list
references section ordering N which does not exist An equation's section_ordering doesn't match any section Ensure the section with that ordering exists and is type equations
missing required attributes: X, Y template_data.py is missing one of the four required exports Add the missing TEMPLATE_META, VARIABLES, SECTIONS, or EQUATIONS
SymPy evaluation error at runtime Invalid expression string Test with from sympy import sympify; sympify("your_expr")
LaTeX not rendering Missing $$ delimiters or unescaped backslashes Use raw strings (r"...") for static LaTeX. For substitution LaTeX, double-escape: \\frac
Substitution placeholders not replaced Missing dot prefix Use .variable_name (with leading dot) in substitution_latex