creating my own context processor in django

42,894

Solution 1

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))

Solution 2

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.

Solution 3

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': '[email protected]'}

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!

Solution 4

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

Solution 5

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.

Share:
42,894
dotty
Author by

dotty

Hmm not alot really.

Updated on July 08, 2022

Comments

  • dotty
    dotty almost 2 years

    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
    dotty about 14 years
    The 'context_instance' is what was missing! Thanks TM
  • dotty
    dotty about 14 years
    Follow up, how come i need this context_instance? How come i don't need this if i use django's auth system?
  • TM.
    TM. about 14 years
    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.
  • dotty
    dotty about 14 years
    Could i modify my view to request the context?
  • TM.
    TM. about 14 years
    @dotty Not sure what you mean by "request the context".
  • suhailvs
    suhailvs almost 11 years
    @TM. return render_to_response('template.html', context_instance=RequestContext(request)) is old fasion, i think return render(request,'template.html') is more DRY
  • TM.
    TM. almost 11 years
    @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.
  • fabspro
    fabspro over 10 years
    Indeed, these days that is possible.
  • ash
    ash over 2 years
    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.