General Shape
Python decides what exists. Jinja decides what shows up.
formless and empty
Notes taken while working with Jinja2
Python decides what exists. Jinja decides what shows up.
The Environment is the hard boundary.
Once templates start rendering, the Environment should be treated as immutable. Changing it afterward is undefined behavior in practice.
Templates assume variables exist and are already in the right shape.
Example:
<title>{{ title }}</title>
<meta name="description" content="{{ description }}">
There is no fallback logic here. If title or description are missing, rendering will fail or output nothing. That is intentional. The template should not try to recover from missing required data.
Another example:
<h4><a href="{{ article.url }}">{{ article.title }}</a></h4>
The template assumes article has a title and url. It does not check types, presence, or structure. Jinja will try attribute access first, then item access. The template does not care which one succeeds.
Filters are used only for formatting output.
data-title="{{ article.title | lower }}"
data-domain="{{ article.domain | lower }}"
Lowercasing is purely for presentation. It does not change the meaning of the value.
{{ domain | lower | replace(' ', '-') }}
This affects how the value is printed, not how it is identified or stored. Slug generation happens in Python.
set is used to avoid repeating expressions inside a template.
{% set count = articles|length %}
{% set maxc = domain_max or 1 %}
{% set pct = (count / maxc * 100) | round(2) %}
These values exist only inside this loop iteration. They are not reused outside of it. Jinja clears assignments at the end of the scope.
If these values were important beyond rendering, they should not be computed here.
Conditionals decide whether something is rendered.
{% if article.division %}
If division exists and is non empty, it renders. Otherwise nothing is output. No attempt is made to infer or synthesize values.
{% if article.worked_hours is not none or article.word_count is not none %}
is not none is used instead of truthiness so that zero is treated as a valid value. Absence and zero are different.
Separators are conditional:
{% if article.worked_hours is not none and article.word_count is not none %} | {% endif %}
This prevents stray punctuation when one value is missing.
Loops iterate over data that has already been prepared.
{% for article in recent_articles %}
Sorting, filtering, and grouping are not done in the template. The template assumes the list is already in the correct order.
{% for domain, articles in categorized_articles.items() %}
Grouping by domain already happened. The template just iterates and displays counts.
Defaults are used to keep rendering from breaking.
{% set action = entry.action | default("MODIFIED") %}
If entry.action is missing, a fallback string is used so layout stays intact. This does not correct the underlying data.
{% set maxc = domain_max or 1 %}
Some Python operations are used when they are straightforward.
media.basename.split('.')[-1]
This extracts a file extension for display. It does not encode logic beyond formatting.
`categorized_articles.items()`
This assumes a dict-like object. No mutation or transformation occurs.
If Python logic grows beyond this, it should move out of the template.
Whitespace behavior is controlled mostly by configuration.
Blocks are placed on their own lines. Output stays compact. Readability is preserved.
Inline trimming is only used when dense output requires it.
Connections
Revisions