render_placeholder exception from lazy RequestContext

36 views
Skip to first unread message

John Bazik

unread,
Feb 17, 2016, 5:44:41 PM2/17/16
to django CMS developers
In Django 1.8, RequestContext() no longer returns a context with a 'request' key until it is "bound" to a template:

  >>> from django.test.client import RequestFactory
  >>> from django.template import RequestContext
  >>> req = RequestFactory().get('/admin/')
  >>> req
  <WSGIRequest: GET '/admin/'>
  >>> context = RequestContext(req)
  >>> context
  [{'False': False, 'None': None, 'True': True}, {}, {}]

I'm working with a third-party plugin that does the following (to maintain a content cache):

  context = RequestContext(request)
  content = render_placeholder(entry.content_placeholder, context)

render_placeholder (from cms.plugin_rendering) accesses context['request'] right at the top, and generates a KeyError exception.  I could fix the plugin code like this:

 context = RequestContext(request)
 with context.bind_template(template):
      content = render_placeholder(entry.content_placeholder, context)

But Placeholders do not have a template.  It seems to me that render_placeholder ought to take an optional request parameter:

 def render_placeholder(placeholder, context_to_copy, name_fallback="Placeholder",
                        lang=None, default=None, editable=True, use_cache=True, request=None):
 ...
     context = context_to_copy.new(context_to_copy)
     context.push()
     if not request:
         if 'request' in context:
             request = context['request']
 ...

Any suggestions for how to fix this?  Did I miss something?

John

John Bazik

unread,
Feb 18, 2016, 4:02:57 PM2/18/16
to django CMS developers
I thought I could get away with just adding "request" to the context in the plugin code:

        context = RequestContext(request)
        context.update({'request': request})
        content = render_placeholder(entry.content_placeholder, context)

But then I tripped up on an AttributeError exception in django.template.context.RequestContext.bind_template(), because that class' "new" method removes an attribute (_processors_index) that is later used by bind_template.

This makes me think that you should not be copying contexts like this:

        context = context_to_copy.new(context_to_copy)

If context_to_copy is not already bound to a template, then context can't be.

For now I've got things working (again in the plugin code) like this:

        from django.template.engine import Engine
        template = Engine.get_default().from_string('')

        with context.bind_template(template):
            content = render_placeholder(entry.content_placeholder, context)

But that's not a general solution since it only works if you have exactly one template engine declared.

John
Reply all
Reply to author
Forward
0 new messages