django-templatesjinja2mako

Custom widgets: The equivalent of Mako's <%def> in Jinja2 or Django templates


I am quite proficient with Mako, but never actually used Jinja or Django templates.

What is Jinja/Django equivalent of Mako <%def name="..."> definition?

Following is a simplified example of my actual use case. I need to define a simple table and use it repeatedly on the page:

<%def name="temperature_table(north, east, south, west)">
    <table>
        <tr>
            <td>North:</td>
            <td>${north}</td>
        </tr>
        <tr>
            <td>East:</td>
            <td>${east}</td>
        </tr>
        <tr>
            <td>South:</td>
            <td>${south}</td>
        </tr>
        <tr>
            <td>West:</td>
            <td>${west}</td>
        </tr>
    </table>
</%def>

<h2>Morning</h2>
${weather_table(20, 21, 22, 23)}

<h2>Afternoon</h2>
${weather_table(22, 22, 25, 24)}

<h2>Night</h2>
${weather_table(17, 16, 17, 18)}

From what I gleaned from various articles, it could seem that blocks are used for this purpose in Jinja/Django. But blocks would introduce inheritance even to simple templates where a custom widget would be sufficient. Other authors suggest creating a custom tag, but, in my opinion, this would require to write custom parsing, rendering, and probably even custom cache managing functions. Am I missing something?


Solution

  • You can use a macro for that.

    As described in the manual:

    Macros are comparable with functions in regular programming languages. They are useful to put often used idioms into reusable functions to not repeat yourself (“DRY”).

    Source: https://jinja.palletsprojects.com/en/3.0.x/templates/#macros

    So, given:

    {% macro weather_table(north, east, south, west) -%}
      <table>
          <tr>
              <td>North:</td>
              <td>{{ north }}</td>
          </tr>
          <tr>
              <td>East:</td>
              <td>{{ east }}</td>
          </tr>
          <tr>
              <td>South:</td>
              <td>{{ south }}</td>
          </tr>
          <tr>
              <td>West:</td>
              <td>{{ west }}</td>
          </tr>
      </table>
    {%- endmacro %}
    
    <h2>Morning</h2>
    {{ weather_table(20, 21, 22, 23) }}
    
    <h2>Afternoon</h2>
    {{ weather_table(22, 22, 25, 24) }}
    
    <h2>Night</h2>
    {{ weather_table(17, 16, 17, 18) }}
    

    It renders your expected tables.

    <h2>Morning</h2>
    <table>
      <tr>
        <td>North:</td>
        <td>20</td>
      </tr>
      <tr>
        <td>East:</td>
        <td>21</td>
      </tr>
      <tr>
        <td>South:</td>
        <td>22</td>
      </tr>
      <tr>
        <td>West:</td>
        <td>23</td>
      </tr>
    </table>
    
    <h2>Afternoon</h2>
    <table>
      <tr>
        <td>North:</td>
        <td>22</td>
      </tr>
      <tr>
        <td>East:</td>
        <td>22</td>
      </tr>
      <tr>
        <td>South:</td>
        <td>25</td>
      </tr>
      <tr>
        <td>West:</td>
        <td>24</td>
      </tr>
    </table>
    
    <h2>Night</h2>
    <table>
      <tr>
        <td>North:</td>
        <td>17</td>
      </tr>
      <tr>
        <td>East:</td>
        <td>16</td>
      </tr>
      <tr>
        <td>South:</td>
        <td>17</td>
      </tr>
      <tr>
        <td>West:</td>
        <td>18</td>
      </tr>
    </table>