[Django]-Django – using a common header with some dynamic elements

9👍

I’m assuming each tab is a list item in your template base.html.

<ul>
    <li>Tab 1</li>
    <li>Tab 2</li>
    ...
</ul>

Add an extra block to each li.

<ul>
    <li class="{% block class_tab1 %}inactive{% endblock %}">Tab 1</li>
    <li class="{% block class_tab2 %}inactive{% endblock %}">Tab 2</li>
    <li class="{% block class_tab3 %}inactive{% endblock %}">Tab 3</li>
    ...
</ul>

Then in your template if tab 1 is to be selected:

{% extends "base.html" %}

{% block class_tab1 %}active{% endblock %}
...

So the html rendered for Tab 1 is:

<ul>
    <li class="active">Tab 1</li>
    <li class="inactive">Tab 2</li>
    <li class="inactive">Tab 3</li>
    ...
</ul>

and you can write CSS to target the li .active as you wish.

1👍

A version of #1 will do the trick — with a separate template file for the tag.

Lets say you have the models “Category” and “Article”.

class Category(models.Model):
    title           = models.CharField(_("Name"), max_length=200)
    introduction    = models.TextField(blank=True, null=True)
    slug            = models.SlugField(help_text=_("Used for URLs"))
    sort_order      = models.IntegerField(_("Sortierung"))

class Article(models.Model):
    title = models.CharField(_("Full Name"), max_length=255)
    slug = models.SlugField(_("Slug Name"), unique=True, help_text=_("This is a short, descriptive name of article that will be used in the URL link to this item"))
    text = models.TextField(_("Text of Article"), blank=True, null=True)
    category = models.ForeignKey(Category)

in your views you would pass the category you are viewing to the template:

@render_to('cat_index.html')
def category_view(request,string):

    cat = Category.objects.get(slug=string)
    articles = Article.objects.filter(category = cat).order_by('date')
    return {
             'articles':articles,
             'category':cat,
             }

(Note: using the annoying render_to-decorator – same as render_to_response)

and in your template you call a inclusion_tag like this:

@register.inclusion_tag('snippets/navigation.html')
def navigation(cat=None):
    return {'cats':Category.objects.order_by('sort_order'),
            'cat':cat
            }

by using this in your base-template (often called base.html)

{% navigation category %}

Now in the inclusions_tags’s template (snippets/navigation.html) you would for-loop over cats and if one of it equals cat you can assign other styles

    <ul>    
      {% for c in cats %}
          <li{% ifequal c cat %} class="active"{% endifequal %}>
              <a href="{{c|url}}">{{ c }}</a>
          </li>
      {% endfor %}
    </ul>

1👍

This is a rather common problems and I’ve come up with some various ways to solve it.

Since you’re asking for options, here’s 3 other alternative ways achieve this effect. The options you mentioned and these listed below all have thier positives and negatives. It’s really up to you to decide which is a best fit.

Alternate 1 – Use Regular Expressions and a Hash Table

This could be performed either client-side (less advantageous) or server-side (a better pick). To do this you could have a tag that had 1 input: a regular expression. In use it would look like this…

// In base.html...

<li class="tab {% is_tab_active r'^/cars/' %}"><a>Cars</a></li>
<li class="tab {% is_tab_active r'^/trucks/' %}"><a>Trucks</a></li>

The custom tag applies the regular expression against the current page being viewed. If successfull, it adds a css class “active” if not “inactive” (or whatever your CSS classes are).

I’ve been pondering this method for a while. I feel as if there should be some good way to come up with a way to tie it into urls.py, but I haven’t seen it yet.

Alternate 2 – Use CSS

If you were to identify each [body] tag, or at least have a common template for the sections of your site, CSS could be used to assign which was active. Consider the following:

body.cars_section .navigation #cars_tab { color: #00000; }
body.truck_section .navigation #trucks_tab { color: #00000; }

For your base template…

<body class="{% block category %}{% endblock %}">

...

<ul class="navigation">
    <li id="cars_tab"><a>Cars</a></li>
    <li id="trucks_tab"><a>Trucks</a></li>

Then for any page you simply put the category it’s a part of (matching the CSS rule)…

{% extends "base.html" %}

...

{% block category %}cars_section{% endblock %}

Alternate 3 – Have Some Bloated Middleware

Django lets you write Middleware to affect the behavior of just about whatever you want. This seems like a bloated and complex route with potential negative performance impact, but I figured I’d at least mention it as an option.

Leave a comment