43

base.html is used as the base template for all other pages. base.html has the navigation bar and in the navigation bar, I want to show the number of messages the user received. Thus, I need to have a variable like {{number_of_messages}} in the base.html.

However, how should I pass this variable to it? Every template extends base.html and is rendered by a function. I don't think returning number_of_messages in all functions is a good way. Is there better way to implement this? How can I pass this variable to all templates?

5
  • 1
    have you look at the django template context processors? perhaps the shortest answer would be to create your own context processors and put it into the TEMPLATE_CONTEXT_PROCESSORS in your settings file. Shall my comments be an answer instead? REF: docs.djangoproject.com/en/dev/ref/templates/api/… Commented Jan 11, 2014 at 13:08
  • hi Yeo, I haven't look at that. Is it possible to achieve this goal by using inclusion tag and putting the inclusion tag inside the base.html? Commented Jan 11, 2014 at 13:11
  • I think based on your main question, a variable in a template is called a context. include tag, does different things, but of course you can pass the context within the included template like {% include "name_snippet.html" with person="Jane" greeting="Hello" %}. But you still need the context somewhere right... docs.djangoproject.com/en/dev/ref/templates/builtins/#include Commented Jan 11, 2014 at 13:14
  • Hope you managed to solve your problem. Let me know if you still have some issue :-) Commented Jan 11, 2014 at 13:19
  • Thanks. I find this good reading and I shall proceed to finish it: b-list.org/weblog/2006/jun/14/… Commented Jan 11, 2014 at 13:22

4 Answers 4

20

I find the simplest steps to passing variables to your base templates in django is to add a context_processor.py file like so:

In your app create context_processors.py and declare your variables e.g.:

# context_processors.py
def message_processor(request):
    if request.user.is_authenticated:
        no_msgs = request.user.profile.msgs
    else:
        no_msgs = 0
    return {
        'messages' : no_msgs
    }

Then register your process or under TEMPLATES in your settings.py file:

TEMPLATES = [
    {
        ...
            'context_processors': [
                ...
                # custom
                'appname.context_processors.message_processor',
            ],
        },
    },
]

And then you will be able to get that variable anywhere in your app as:

{{ messages }}
Sign up to request clarification or add additional context in comments.

3 Comments

This answer is straight gold. I love you Josh
Fantastic. This way I could display in navigation bar a selection of items based on a DB query. Don't forget to add request parameter even if you don't use is in your processor.
My use case was putting a "Request access" mailto link in the generic headline of my site, where I needed the target email to be dynamically pulled from the auth_user table. This technique, combined with stackoverflow.com/questions/20400767/… , allowed me to do it.
18

You can use tags.

#myproject/myproject/templatetags/tags.py

from django import template

register = template.Library()

@register.simple_tag
def number_of_messages(request):
    return _number

In your Base.html

{% load tags %}
    {% number_of_messages request %}

2 Comments

Thank you! Another question, should the tags.py be under templates folder?
Sorry. tags.py should be under templatetags.
17

Have a look at:
https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.RequestContext

As long as:

  • you use the render shortcut in your view (or otherwise take care to use a RequestContext to render your response)
  • have django.contrib.auth.context_processors.auth in your TEMPLATE_CONTEXT_PROCESSORS setting (as it is by default)

...then you have the current request's User (or AnonymousUser) instance available in your template as {{ user }} ...I am guessing from there you may be able to access the number of messages directly?

Or perhaps you are using Django's messages framework?

This comes with it's own context processor which (as long as you use render or RequestContext) will make a {{ messages }} var (containing the messages for current user) available in your templates. For 'number of messages' you can do {{ messages|length }}

If none of these built-in options provide what you need you can either:

  • make your own template context processor which will run for every request and make additional variables available to all templates (when rendered with a RequestContext)

  • make your own template tag which can be used only where needed... of course if this is used in your base.html and all templates inherit from base.html then it's still going to run for every page.

Comments

3

If you want the variable in really all the views, then a custom template context processor is probably the best option.

https://docs.djangoproject.com/en/dev/ref/templates/api/#subclassing-context-requestcontext

If you want the variable only in some of the views, then you can make those views call a common function that populates the common variables, something like this:

def some_view(request):
    params = _common_params(request)
    params.update({
        # params specific to .some_view
    })
    return render_to_response('path/to/template, params)

or create a custom decorator like this:

from functools import wraps

def render_with_params():
    def _inner(view_method):
        def _decorator(request, *args, **kwargs):
            params = _common_params(request)
            (template_path, view_params) = view_method(request, *args, **kwargs)
            params.update(view_params)
            return render_to_response(template_path, params, context_instance=RequestContext(request))
        return wraps(view_method)(_decorator)
    return _inner

@render_with_params()
def some_view(request):
    params = { ... }
    return ('path/to/template', params)

1 Comment

Thank you! I think in my situation, I should use context processor since I need to have the variable in all templates. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.