Search code examples
pythonjinja2

import python libraries in jinja2 templates


I have this template:

% template.tmpl file:
% set result = fractions.Fraction(a*d + b*c, b*d) %}
The solution of ${{a}}/{{b}} + {{c}}/{{d}}$ is ${{a * d + b*c}}/{{b*d}} = {{result.numerator}}/{{result.denominator}}$ 

which I invoke by

from jinja2 import Template
import fractions

with open("c.jinja") as f:
    t = Template(f.read())
    a = 2
    b = 3
    c = 4
    d = 5
    print(t.render(a = a, b = b, c=c, d=d))

I get

jinja2.exceptions.UndefinedError: 'fractions' is undefined

but I want

The solution of $2/3 + 4/5$ is $22/15=22/15$.

Is this possible to achieve that?


Solution

  • It can be done in two ways.

    1. Calculate the result in Python code and then pass it as a parameter to the template.
    2. You can pass the fractions module as a parameter to the template.

    Folder structure:

    .
    ├── c.jinja
    └── template_example.py
    

    Option 1: Pass result to the template:

    template_example.py:

    from jinja2 import Template
    import fractions
    
    with open("c.jinja") as f:
        t = Template(f.read())
        a = 2
        b = 3
        c = 4
        d = 5
        result = fractions.Fraction(a * d + b * c, b * d)
        print(t.render(a=a, b=b, c=c, d=d, result=result))
    

    c.jinja:

    The solution of ${{a}}/{{b}} + {{c}}/{{d}}$ is ${{a * d + b*c}}/{{b*d}} = {{result.numerator}}/{{result.denominator}}$
    

    Option 2: Pass the fractions:

    template_example.py:

    from jinja2 import Template
    import fractions
    
    with open("c.jinja") as f:
        t = Template(f.read())
        a = 2
        b = 3
        c = 4
        d = 5
        print(t.render(a=a, b=b, c=c, d=d, fractions=fractions))
    

    c.jinja:

    {% set result = fractions.Fraction(a*d + b*c, b*d) %}
    The solution of ${{a}}/{{b}} + {{c}}/{{d}}$ is ${{a * d + b*c}}/{{b*d}} = {{result.numerator}}/{{result.denominator}}$
    

    Output for both options:

    The solution of $2/3 + 4/5$ is $22/15 = 22/15$
    

    I would recommend Option 1: Pass the result to the template. This approach keeps the template focused on its primary role: rendering text with provided data, while the Python code handles all the computations.