Rendering template tags with `Template` and `TemplateResponse`

My app uses htmx, so I’m able to update only a part of a page. To be able to do so I have one view that renders the full page and one that is supposed to render just a part of the page. To prevent duplication I created a template tag for the relevant part. So in my main template I have:

{% load posts %}
...
<div>
    {% post_status post %}
    ...
</div>

In another view I only want to render {% post_status post %}. Creating I file for that sound like overkill so I tried to give the Template class a try and ended up with:

def post_status(request, post):
    ...
    template = Template("{% load posts %}{% post_status post %}")
    return TemplateResponse(request, template, context={"post": post})

It results in the following error:

Internal Server Error: ...
Traceback (most recent call last):
  File "/opt/development/homework/venv/lib/python3.12/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/development/homework/venv/lib/python3.12/site-packages/django/core/handlers/base.py", line 220, in _get_response
    response = response.render()
               ^^^^^^^^^^^^^^^^^
  File "/opt/development/homework/venv/lib/python3.12/site-packages/django/template/response.py", line 114, in render
    self.content = self.rendered_content
                   ^^^^^^^^^^^^^^^^^^^^^
  File "/opt/development/homework/venv/lib/python3.12/site-packages/django/template/response.py", line 92, in rendered_content
    return template.render(context, self._request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Template.render() takes 2 positional arguments but 3 were given

I checked the source code of TemplateResponse and passing in a Template instance should be fine. I actually don’t see where the 3rd argument is.

Can somebody explain to me what’s going wrong here? Or how to approach the problem of using a snippet standalone and in another template in a better way?

  1. You’re creating a bare Template object that doesn’t have the same interface as the templates Django typically uses with TemplateResponse. Is there a reason for that?

  2. Try to use the render_to_string()

from django.template.loader import render_to_string
from django.http import HttpResponse

def post_status(request, post):
    context = {"post": post}
    html = render_to_string("post_status_snippet.html", context, request=request)
    return HttpResponse(html)

I don’t have a definitive answer for this specific error, but I can tell you what we do for this situation.

We actually do one of two things depending upon the situation:

  1. We create separate template files for the individual “segments” to be returned to HTMX, and use the include tag in the main template when we’re rendering the entire page.

  2. We use render_to_string as described above.