Question

I have a number of templates that extend base.html. I want the base.html template to house my global navigation and have the text and links in the global navigation be based on a model Division (i.e. the CharField in the model will be used as the button text in the global nav, and the id will be used to build the URL). I thought tags might work, but what I end up with is this (yes, I'm new to Django and Python):

current_tags.py

from django import template
# Import your model
from libs.display.models import Division
from django.db import models

register = template.Library()
@register.simple_tag
def do_get_divisions(self):
    d = Division.objects.all()
    mylist = []
    for each in d:
        mylist.append(str(each.DivisionValue))
    return my list

I'm attempting just getting the text value in each object to print at this point because I can't get or work with the objects in the template, as you'll see below.

base.html

<!DOCTYPE html>
<html>
<head>
    {% load staticfiles %}
    <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}style.css" />
</head>
<body>
{% load current_tags %}
<p>{% do_get_divisions "" %}</p> **THIS ACTUALLY PRINTS mylist**

{% for each in do_get_divisions %} **THIS DOESN'T PRINT ANYTHING**
    <p>{{ each }}</p>
{% endfor %}  
{% block content %}
{% endblock %}
</body>
</html>

I'm sure there is a better way to do global nav based on a model in Django. I basically want to get all the Division objects and put them into a <ul> to use as my global nav in base.html. I am not that familiar with Django, but my views.py don't help me because I am rendering other templates, not base.html, which are extending base.html. For what it's worth, here's one views.py, where /display/info.html template extends base.html:

# Create your views here.
from django.http import HttpResponse
from apps.pulldata.models import Data
from django.shortcuts import render, get_object_or_404
from django.http import Http404

def info(request, group_id):
    group = get_object_or_404(Data, pk=group_id)
    s = group.XInGroup.all()
    return render(request, 'display/info.html', {'Group': group, 's': s})
Was it helpful?

Solution

You cannot put a templatetag into another. Your for-loop is a templatetag that expects the name of an element in your context to iterate over.

If you want to handle the navigation in a template tag you should consider using inclusion tags.

Inclusion tags are functions that use templates to render their data.

A very basic implementation could look something like this:

tags.py

@register.inclusion_tag('navigation.html')
def navigation(selected_id=None):
    return {
        'navigation': Division.objects.all(),
        'selected':selected_id,
    }

In your templatetag file you create a dictionary with the navigation items and optionally the currentl selected item to highlight this navigation element.

navigation.html

<ul>
{% for item in navigation %}
  <li{% if item.id == selected %} class="selected"{% endif %}>
    <a href="{{ item.get_absolute_url }}">{{ item.DivisionValue }}</a>
  </li>
{% endfor %}
</ul>

the navigation.html uses the dictionary from the python function as context so you start with simply iterating over the navigation.

base.html

{% navigation %}

or

{% navigation current_division.id %}

In the base.html you call the inclusion tag like a normal template tag. if you want to highlight the current item you add its id as a argument.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top