10

I am trying to pass variables (browser variable) to all my templates in my app. Any advice on how to get it to work?

View:

def browser(request):
    primary_cat_list = Categories.objects.order_by("category")
    subcat_list = SubCategories.objects.order_by("sub_category")
    product = Productbackup.objects.order_by("website")
    browser =  list(chain(primary_cat_list, subcat_list, product))
    return render_to_response('reserve/templates/base.html', locals(), context_instance=RequestContext(request))

Template:

{% for prod in browser %} {{ prod }}, {% endfor %}
sharataka
  • 5,014
  • 20
  • 65
  • 125
  • I'm not sure if this has anything to do with it, but it is strange your function is named `browser` and you are also assigning to a variable called `browser`. I did some experiments in a python shell and that doesn't seem to be the issue, but you might want to change it to make it less confusing. – Brian Neal Aug 20 '12 at 03:10
  • Also make sure that your list is not empty. Try using the debugger or print the value in your view. – Brian Neal Aug 20 '12 at 12:58
  • And, are you really asking how to get variables to show up in all templates, or why in this particular case the `browser` variable isn't working? – Brian Neal Aug 20 '12 at 13:34
  • @BrianNeal I initially wanted to to know why the browser variable wasn't being passed to base.html. This would effectively allow me to use the variable across all templates, which is really what I'm trying to do. – sharataka Aug 21 '12 at 13:31

3 Answers3

14

You, my friend, are in the market for Context Processors.

From a blog entry written by a far nimbler and erudite technical writer than I:

What are template context processors?

Django’s context processors are a facility that allows you to provide data and callbacks to your templates.

You can do so in one of two ways:

  • On an individual request basis: by passing a custom Context value to your render_to_response() call
  • Globally: by creating a context processor method that accepts a HttpRequest object as input, and returns a payload or callback, then registering the context processor in your settings.py, then providing your render_to_response() call with the built-in RequestContext attribute instead of your own (you can always extend RequestContext to add more data on an individual request basis of course).

If that approach for passing data to templates sounded absurd and obfuscated to you, you’re not alone. The complexity involved in such a simple operation is unwarranted and counter-productive, but every system has its shortcomings.

The official documentation is here:

https://docs.djangoproject.com/en/dev/ref/templates/api/

So but yeah, I have been programming with Django for a while, and one of the reasons I really like solving problems w/ it is because it is almost Byzantine in its complexity, but not in a domineering sort of way. It has a ton of geegaws and doodads that may not immediately appear useful; each of these either comes in extremely handy when you need it, and it will stay out of your way if not.

The upshot here for you is: context processors are a fine example of those. Yes.

fish2000
  • 4,289
  • 2
  • 37
  • 76
  • Wasn't that what the OP was asking for?... I am inclined to agree on a personal level w/r/t overkill as I don't generally work this way. But I can't say for sure either way, so it's best left as a programmers' adventure, the educational experience of which far eclipse any comments I could make. Anyway, that is why I added the ¶ at the end, as the Q sounded like someone who was exploring the framework as much as solving a specific technical problem. – fish2000 Aug 20 '12 at 08:11
4

Currently you're passing locals() as the variable scope which should include browser aswell, but I find the use of locals() very ugly.

Personally I always prefer a pattern like this instead:

def browser(request):
    context = RequestContext(request)

    primary_cat_list = Categories.objects.order_by("category")
    subcat_list = SubCategories.objects.order_by("sub_category")
    product = Productbackup.objects.order_by("website")
    browser =  list(chain(primary_cat_list, subcat_list, product))

    context['browser'] = browser

    return render_to_response('reserve/templates/base.html', context_instance=context)
Wolph
  • 78,177
  • 11
  • 137
  • 148
  • This doesn't seem to work...base.html still isn't displaying anything. – sharataka Aug 19 '12 at 23:20
  • 1
    @sharataka: in that case perhaps the list is simply empty? What if you do something like this: `browser = ['spam', 'eggs']`? – Wolph Aug 20 '12 at 10:21
4

I can give you an example of my code, that works fine. Here is the file named context_processors.py:

context_processors.py

def base(request):
    user = request.user

#======================
#Login form
#=====================

# here is the code for login user or check if he is logged in already

return  {
        'user': user,
        }

and that's, part of my base.html (a template that I use wor all my pages)

base.html

{% if user.username %}
                    <h3>
                        Welcome {{ user.username }}
                    </h3>
Community
  • 1
  • 1
Vor
  • 33,215
  • 43
  • 135
  • 193