When you calltemplate.render_block("block_name", context), the block is rendered in isolation. It does not have access to {% def %}macros defined in the same template.
The Problem
{# page.html — def and block in same file #}
{% def helper() %}shared logic{% end %}
{% block content %}
{{ helper() }} {# NameError or UndefinedError when using render_block #}
{% end %}
If a framework (e.g. Chirp) calls template.render_block("content", ...), the block cannot see helperbecause blocks are compiled with their own scope.
Fix
Split defs into a separate file and import them:
{# _helpers.html #}
{% def helper() %}shared logic{% end %}
{# page.html #}
{% from "_helpers.html" import helper %}
{% block content %}
{{ helper() }}
{% end %}
Now both full-page render() and render_block("content", ...) work, because the block imports helperfrom another template.
When This Matters
- Fragment rendering — Chirp and similar frameworks use
render_block()to return HTML fragments for htmx, SSE, etc. - Block caching — Site-scoped block caching renders blocks individually via
render_block().
See Also
- Functions and macros —
{% def %}and{% from %} - Block caching — Caching individual blocks