What would cause the same Django template include block to behave differently twice on the same page?

Viewed 61

I'm trying to include a simple pagination template into a template that lists blog posts, but it gets output without getting interpreted, as in, I see the double curly brace enclosed tag as text in the resultant webpage (see image below).

Strangely, when I also paste same block higher in the page, and it gets interpreted fine. The same include, twice on the same page, different behavior!

Between the two, I iterate over the same object that gets passed to the pagination template, so this is probably something that I don't understand about the state of that object? Or Django's rendering process.

{% extends "blog/base.html" %} 
{% block title %}My blog site thing{% endblock %}
{% block content %}
    <h1>Blog site</h1>
    {% include 'pagination.html' with page_object=posts %} 
    {% for post in posts %}
        <h2><a href="{{post.get_absolute_url}}">{{ post.title }}</a></h2>
        <p class="date">Published {{post.publish}} by {{post.author}}</p>
        {{post.body|truncatewords:5|linebreaks}}
    {% endfor %}
    {% include 'pagination.html' with page_object=posts %}
    {% endblock %}

Pagination.html

<div class="pagination">
  <span class="step-links">
    {% if page_object.has_previous %}
    <a href="?page={{ page_object.previous_page_number }}">Previous</a>
    {% endif %}
    <span class="current">
      Page {{ page_object.number }} of {{ page_object.paginator.num_pages }}.
    </span>
    {% if page_object.has_next %}
    <a href="?page={{ page_object.next_page_number }}">Next</a>
    {% endif %}
  </span>
</div>

views.py for this app

from django.shortcuts import render, get_object_or_404
from .models import Post
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger


def post_list(request):
    object_list = Post.published.all()
    paginator = Paginator(object_list, 3)
    page = request.GET.get('page')
    try:
        posts = paginator.page(page)
    except PageNotAnInteger:
        posts = paginator.page(1)
    except EmptyPage:
        posts = paginator.page(paginator.num_pages)
    
    return render(request, 'blog/post/list.html', {'posts':posts})

def post_detail(request, year, month, day, post):
    post = get_object_or_404(Post, slug=post, status='published',publish__year=year,publish__month=month, publish__day=day)
    return render(request, 'blog/post/detail.html', {'post':post})

Here's what the resultant page looks like: Screenshot of the page render via the html below

Here's the resultant html (I've added an extra line around the offending output to call it out)

<!DOCTYPE html>
<html>
  <head>
    <title>My blog site thing</title>
    <link href="/static/css/blog.css" rel="stylesheet">
  </head>
</html>
<body>
  <div id="content">
<h1>Blog site</h1>
<div class="pagination">
  <span class="step-links">
    
    <span class="current">
      Page 1 of 2.
    </span>
    
    <a href="?page=">Next</a>
    
  </span>
</div>
 
<h2><a href="/blog/2022/3/2/another-glorious-post/">Another glorious post</a></h2>
<p class="date">Published March 2, 2022, 9:26 p.m. by admin</p>
<p>Lorem ipsum text Lorem ipsum …</p> 
<h2><a href="/blog/2022/3/2/classy-post/">Classy post</a></h2>
<p class="date">Published March 2, 2022, 9:25 p.m. by admin</p>
<p>This is the way</p> 
<h2><a href="/blog/2022/3/1/another-post/">Another post</a></h2>
<p class="date">Published March 1, 2022, 7:26 a.m. by admin</p>
<p>Xyz</p>  

{% include 'pagination.html' with page_object=posts %}

</div>
  <div id="sidebar">
    <h2>My blog</h2>
    <p>This is my blog.</p>
  </div>
</body>

I've even gone back and copy-pasted the actual code from the book I'm following (Django 3 by example, by Antonio Mele) and it's identical!

To any kind soul who has read this far, what am I missing?

1 Answers

Ok, so I just understood what was going on, and sharing in case it's useful to anyone else.

My IDE was mangling the formatting of the template file on save.

So the first include was a perfect little

{% include 'pagination.html' with page=posts %}

The second one ended up looking like

{% include 
    'pagination.html' with page=posts %}

When I turned off the auto-formatting and fixed the whitespace, it rendered fine.

So my big learning – probably obvious to many – is that whitespace matters in django template tags!.

Related