ThatAintWorking
ThatAintWorking

Reputation: 1360

django custom templatetag not getting request in context

I am using django 1.4 and trying to convert the code described at the end of this article into a customtag. This means I need access to the is_secure and site_name values from the request. Here is my CONTEXT_PROCESSORS in settings.py:

CONTEXT_PROCESSORS = (
    'django.core.context_processors.request',
    'django.contrib.auth.context_processors.auth',
)

Here is my template tag code:

from django import template
register = template.Library()

@register.simple_tag(takes_context=True)
def full_static_url(context, url):
    request = context['request']
    scheme = 'http'
    if request.is_secure:
        scheme += 's'
    return scheme + '://' + request.site_name + context['STATIC_URL'] + url

In my view code I am using the new render shortcut like so:

return render(request, 'myapp/mytemplate.html', {'foo':bar})

And I am calling it like this in the template:

{% full_static_url "images/logo.gif" %}

The problem is, when it gets to the line request = context['request'] it throws a KeyError because 'request' is not in context.

What am I doing wrong here?

Full traceback is:

File "C:\Python27\lib\site-packages\django\core\handlers\base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "C:\Projects\blah\blah\myapp\views\myview.py" in manifestcosts
  44.     return render(request, 'myapp/mytemplate.html', {'foo':bar})
File "C:\Python27\lib\site-packages\django\shortcuts\__init__.py" in render
  44.     return HttpResponse(loader.render_to_string(*args, **kwargs),
File "C:\Python27\lib\site-packages\django\template\loader.py" in render_to_string
  176.         return t.render(context_instance)
File "C:\Python27\lib\site-packages\django\template\base.py" in render
  140.             return self._render(context)
File "C:\Python27\lib\site-packages\django\template\base.py" in _render
  134.         return self.nodelist.render(context)
File "C:\Python27\lib\site-packages\django\template\base.py" in render
  823.                 bit = self.render_node(node, context)
File "C:\Python27\lib\site-packages\django\template\debug.py" in render_node
  74.             return node.render(context)
File "C:\Python27\lib\site-packages\django\template\defaulttags.py" in render
  185.                         nodelist.append(node.render(context))
File "C:\Python27\lib\site-packages\django\template\base.py" in render
  1107.                     return func(*resolved_args, **resolved_kwargs)
File "C:\Projects\blah\blah\myapp\templatetags\mytags.py" in full_static_url
  25.     request = context['request']        #TODO this fails with an KeyError, don't know why
File "C:\Python27\lib\site-packages\django\template\context.py" in __getitem__
  54.         raise KeyError(key)

Exception Type: KeyError at /myapp/myurl/110505081136179000/
Exception Value: 'request'

Upvotes: 3

Views: 7781

Answers (4)

lithiium
lithiium

Reputation: 647

The right way to fix this issue is to add TEMPLATE_CONTEXT_PROCESSORS += ("django.core.context_processors.request",) on your settings.py file.

Ensure to import TEMPLATE_CONTEXT_PROCESSORS first with from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS or it will not work.

Upvotes: 10

Jorticus
Jorticus

Reputation: 3

I had this happen in a template.Node object in the render(). It turned out that sometimes the context had 'request' in it, other times it didn't.

Like someone else suggested, RequestContext(request) is the key. My guess is that sometimes the context is called without the request being initialized like that.

I changed my function from

 def render(self, context):
      request = context['request']  # Failing here

to

 def render(self, context):
      request = RequestContext(context)['request']['request']

and it all came right.

This will force a request object in case the context object wasn't initialized properly. For some reason I had to add ['request'] twice, but it seems to work fine


EDIT: I spoke too soon, seems a blank context can't be fixed. Instead you could try a workaround:

request = context.get('request')
if request is None:
    return ''

My page still seems to work fine, so I'm not exactly sure where these bad contexts are coming from.

Upvotes: 0

Pheonix
Pheonix

Reputation: 6052

I solved it by changing

return render(request, 'myapp/mytemplate.html', {'foo':bar})

to

return render( RequestContext(request), 'myapp/mytemplate.html', {'foo':bar})

I hope this helps someone else, I wasted about 8 hours :p

Upvotes: 0

koniiiik
koniiiik

Reputation: 4382

Most likely the problem is you are rendering your template using regular context, that is something like this:

return render_to_response("myapp/template.html", {"some_var": a_value})

Remember that context processors are only applied to RequestContext instances. That means you have to either explicitly create a RequestContext in your render_to_response call:

return render_to_response("myapp/template.html", {"some_var": a_value},
                          context_instance=RequestContext(request))

or even better, use the new render shortcut:

return render(request, "myapp/template.html", {"some_var": a_value})

Upvotes: 1

Related Questions