95

I have come to a point where I need to pass certain variables to all of my views (mostly custom authentication type variables).

I was told writing my own context processor was the best way to do this, but I am having some issues.

My settings file looks like this

TEMPLATE_CONTEXT_PROCESSORS = (
    "django.contrib.auth.context_processors.auth",
    "django.core.context_processors.debug",
    "django.core.context_processors.i18n",
    "django.core.context_processors.media",
    "django.contrib.messages.context_processors.messages",
    "sandbox.context_processors.say_hello", 
)

As you can see, I have a module called 'context_processors' and a function within that called 'say_hello'.

Which looks like

def say_hello(request):
        return {
            'say_hello':"Hello",
        }

Am I right to assume I can now do the following within my views?

{{ say_hello }}

Right now, this renders to nothing in my template.

My view looks like

from django.shortcuts import render_to_response

def test(request):
        return render_to_response("test.html")
dotty
  • 40,405
  • 66
  • 150
  • 195
  • I had the same problem and the solution here worked for me : [Use takes_context=True when using register.inclusion_tag](https://stackoverflow.com/a/59452521/5796086) – Laurent Lyaudet Jun 22 '22 at 10:24

5 Answers5

57

The context processor you have written should work. The problem is in your view.

Are you positive that your view is being rendered with RequestContext?

For example:

def test_view(request):
    return render_to_response('template.html')

The view above will not use the context processors listed in TEMPLATE_CONTEXT_PROCESSORS. Make sure you are supplying a RequestContext like so:

def test_view(request):
    return render_to_response('template.html', context_instance=RequestContext(request))
TM.
  • 108,298
  • 33
  • 122
  • 127
  • 1
    The 'context_instance' is what was missing! Thanks TM – dotty May 23 '10 at 22:31
  • 1
    Follow up, how come i need this context_instance? How come i don't need this if i use django's auth system? – dotty May 23 '10 at 23:19
  • 3
    Django's built in views handle this for you (they use a `RequestContext`). Think about the context processor that you made. It takes `request` as an argument. That means you need to somehow give the current request to the rendering logic. `RequestContext` basically just handles the simple logic of looping through all the context processors and passing the current request to them, then updating the page context with the results. – TM. May 23 '10 at 23:31
  • Could i modify my view to request the context? – dotty May 24 '10 at 08:16
  • @dotty Not sure what you mean by "request the context". – TM. May 24 '10 at 16:56
  • 4
    @TM. `return render_to_response('template.html', context_instance=RequestContext(request))` is old fasion, i think `return render(request,'template.html')` is more DRY – suhailvs Aug 02 '13 at 06:12
  • @suhail doesn't that require a special third-party decorator on the view function? The answer is out of date in general (over 3 years old!), probably these days there would be a class-based view here. – TM. Aug 02 '13 at 21:22
32

According to the django docs you can use render as a shortcut instead of render_to_response with the context_instance argument:

Alternatively, use the render() shortcut which is the same as a call to render_to_response() with a context_instance argument that forces the use of a RequestContext.

trpt4him
  • 1,646
  • 21
  • 34
nulse
  • 862
  • 1
  • 8
  • 18
21

Let's say you have a file structure like this:

YourDjangoProject
├───project
│   ├───__init__.py
│   ├───asgi.py
│   ├───settings.py
│   ├───urls.py
│   └───wsgi.py
├───.env
├───manage.py
└───db.sqlite3

1) Anywhere, create a context_processors.py file

I'll create one in the project folder (with settings.py):

YourDjangoProject
└───project
    ├───...
    └───context_processors.py

2) Create a function in context_processors.py that accepts a HttpRequest object as an argument and returns a dictionary

A context processor is just a function that accepts an HttpRequest object as an argument and returns a dictionary.

Like this:

# project/context_processors.py

def site_email(request):
    return {'site_email': 'example@gmail.com'}

3) Add this to your context_processors setting in settings.py (at the bottom for security reasons)

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'config' / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'project.context_processors.site_email',  # <- New context processor here
            ],
        },
    },
]

Now you'll be able to access the 'site_email' template variable on every single django template across your whole site.

Happy coding!

Zack Plauché
  • 3,307
  • 4
  • 18
  • 34
  • 1
    Very Very sorry @Zack But it's a really awesome answer. Given you an upvote. Really helped me to understand a very important concept of Django. Seen your profile You really have a Great vision for Humanity and the future. Hope to see you succeed in your vision. keep Smiling like that. – ash Feb 21 '22 at 18:18
10

Since Django 1.8 you register your custom context processors like this:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            'templates'
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'www.context_processors.instance',
            ],
        },
    },
]

assuming your context processor is in app www in context_processors.py

andilabs
  • 22,159
  • 14
  • 114
  • 151
2

If you’re using Django’s render_to_response() shortcut to populate a template with the contents of a dictionary, your template will be passed a Context instance by default (not a RequestContext). To use a RequestContext in your template rendering, use the render() shortcut which is the same as a call to render_to_response() with a context_instance argument that forces the use of a RequestContext.

M.javid
  • 6,387
  • 3
  • 41
  • 56
GrvTyagi
  • 4,231
  • 1
  • 33
  • 40