Having trouble with Django inclusion_tag seeming to have recursive calls

Viewed 20

Sorry in advance for the length, I wanted to do my due diligence and also provide as much detail as necessary.

I have a navbar template file that is included into a header template file, which is then extended by my rendered templates. In the navbar I want to be able to have a bubble on a menu item that shows how many pending requests there are for a particular model.

I've followed this doc over and over and still can't figure out what the issue is. Confusing me even more in my searches are the similar issues others have had but using different versions of Django so I've used the Django doc as the main reference.

It seems that the function (the one that is the inclusion tag) is getting called recursively because, while debugging I noticed it runs through once and the request dictionary key is in the context. However, it runs through a second time and at that point there is no request key so it fails. I put it in a try/except block to skip over the error and see what would happen but then it throws a recursive limit reached error.

Can someone help with this and help me figure out why this is throwing that error?

The Error

  File "/Users/geoffberl/git/python/family_tools_django_site/toolpool/templatetags/tool_requests.py", line 10, in get_tool_requests_count
    owner = context['request'].user
  File "/Users/geoffberl/git/python/family_tools_django_site/venv/lib/python3.10/site-packages/django/template/context.py", line 83, in __getitem__
    raise KeyError(key)
KeyError: 'request'

I've created a sample project with some slimmed down code to reproduce he issue.

The Project Structure

(in Django 4.1)

  • app
    • main
      • templates
        • header.html
        • home.html
        • navbar.html
      • templatetags
        • __init__.py
        • tag_stuff.py
      • Other common files not typed out (admin, url, apps, etc)

header.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Family Tools{% endblock %}</title>
    <!--Bootstrap CSS-->
    <link href="{% static '/bootstrap/css/bootstrap.css' %}" rel="stylesheet">
    {% include "main/navbar.html" %}
</head>
<body>

{% block content %}

{% endblock %}

<!-- Optional Javascript -->
<script src="{% static '/bootstrap/js/jquery.js' %}"></script>
<script src="{% static '/bootstrap/js/bootstrap.js' %}"></script>
<script src="{% static 'js/jquery.bootstrap.modal.forms.min.js' %}"></script>
</body>
</html>

home.html

{% extends 'main/header.html' %}
{% block content %}

    <h1>Select a tool:</h1>
    <form action="{% url 'toolpool:index' %}">
        <input type="submit" value="Tool Pool"/>
    </form>

{% endblock %}

navbar.html

{% load tag_stuff %}
{% get_tool_requests_count %}
<!--Navbar-->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
    <a class="navbar-brand" href="{% url 'main:homepage' %}">Family Tools</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText"
            aria-controls="navbarText" aria-expanded="False" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarText">
        <ul class="navbar-nav mr-auto">
            {% if user.is_authenticated %}

                <li class="nav-item">
                    <a class="nav-link" href="/logout">Logout</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">Welcome, {{ user.username }}</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="{% url 'main:friend_requests' %}">Friend Requests</a>
                </li>
                <li class="nav-item">
                    <p>You have {{ tool_requests_count }} requests</p>
                </li>

            {% else %}

                <li class="nav-item">
                    <a class="nav-link" href="/login">Login</a>
                </li>

            {% endif %}
        </ul>
    </div>
</nav>

views.py

from django.shortcuts import render

# Create your views here.


def homepage(request):
    return render(request=request, template_name='main/home.html')

tool_requests.py

from django import template

register = template.Library()


@register.inclusion_tag('main/navbar.html', takes_context=True)
def get_tool_requests_count(context):
    owner = context['request'].user

    # Ideally some model query here which would need the 'owner' obtained above in order to get count of items.
    item_count = 12

    return {'tool_requests_count': item_count}

Here is a zip of the entire project if anyone is kind enough to want to reproduce the issue themselves. https://drive.google.com/file/d/1O8jwjyMvzKD4Ef0-6uN-Ju9N2YAS8R7U/view?usp=sharing

For full disclosure, this was originally posted on Reddit r/Django but doesn't seem to have many views. https://www.reddit.com/r/django/comments/xg0gwr/help_with_providing_model_data_to_a_partial/

1 Answers

Thanks to philgyford on Reddit, this issue has been solved. It appears I was incorrectly using an Inclusion Tag when what I should have been using was a Simple Tag.

Updated tool_requests.py

from django import template

register = template.Library()


@register.simple_tag(takes_context=True)
def get_tool_requests_count(context):
    owner = context['request'].user

    # Ideally some model query here which would need the 'owner' obtained above in order to get count of items.
    item_count = 12

    return item_count
Related