3

I have a Django template, let's call it index.html which is divided in 3 parts (header, content and footer). In the header section I have a search bar that includes a drop-down menu which allows the user to select an option from it and search things based on the selected option. I want that header section to be include in all my future views/templates and still display the drop-down menu with all the options.

This is what I currently have in my view file

def index(request):
    return render(
                    request,
                    'home.html',
                    {'categories': get_all_categories()}
                )


def cart(request):
    return render(request, 'cart.html', {'categories': get_all_categories()})


def help(request):
    return render(request, 'help.html', {'categories': get_all_categories()})


def about(request):
    return render(request, 'about.html', {'categories': get_all_categories()})


def contact(request):
    return render(request, 'contact.html', {'categories': get_all_categories()})


def search(request):
    return render(request, 'search.html', {'categories': get_all_categories()})


def get_all_categories():
    return Category.objects.all()

This is what I have cart.html {% extends "index.html" %}

{% block content %}

<div>
<h1> My Cart </h1>
</div>

{% endblock %}

This is what contact.html has {% extends "index.html" %}

{% block content %} 

<div>
<h1> Contact </h1>
</div>

{% endblock %} 

This is what home.html contains {% extends "index.html" %}

{% block content %}

<div>
<h1> Home </h1>
</div>

{% endblock %}

This works right now but I was wondering if there was a better way to solve this so that I don't have to repeat the same code in all of the views.

2 Answers2

2

You could write a custom context processor to include that variable in every template you render.

For example, write a context processor like the following (in context_processors.py, say):

def category_context_processor(request):
    return {
        'categories': get_all_categories(),
    }

And include it in settings.py:

TEMPLATES = [
    ...
    'OPTIONS': {
        'context_processors': [
            ...
            'myapp.context_processors.category_context_processor',
        ],
    },
}

Now the variable categories is available in every template you render (using the render call or a RequestContext, anyway), regardless of the context you actually pass from the view.

Ben
  • 6,687
  • 2
  • 33
  • 46
0

You can also use a template tag.

polls/
    __init__.py
    models.py
    templatetags/
        __init__.py
        poll_extras.py
    views.py

In yours poll_extras.py file

from django import template

register = template.Library()

@register.simple_tag
def get_categories(request, arg1, arg2, ...):
    return {
        'categories': get_all_categories(),
    }

Or you can use a inclusion_tag with its own template (staying the same in all views):

@register.inclusion_tag('categories_block_template.html')
def get_categories(arg1, arg2, *args, **kwargs):
    categories = Category.objects.filter(field1=arg1, ...)
    ...

And finally, in the template you need to load the templatetag and use it:

{% load poll_extras %}

You can see more about templatetags here

Gil Guilherme
  • 252
  • 1
  • 5