Reputation: 107
I have a website with a menu. To generate the menu, I need some queries in the database. So I created a context processor to do it in all my views.
Some of the views I have are actually forms. I get them using ajax and display them with jquery ui dialog, when my users click on some buttons.
I can't remove all context processors for those pretty complex forms, I need the auth, static and il8n context processors in particular. But I don't want to make the menu based queries in the database to display those forms.
Is there a way to exclude a context processor in a view ? I tried to put a variable in "request.session" in the view, then remove it and return an empty dictionary in my context processor. But it's pretty bad and there is possible concurrency issues. I can also parse the url in "request" in my context processor and return an empty dictionary, but it sounds like an hack again.
Any idea or advice ? Thanks,
Upvotes: 1
Views: 3081
Reputation: 14212
That's very easy to achieve using various template engines.
TEMPLATES = [
# The default engine - a heavy one with a lot of context processors
{
'NAME': 'default',
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.i18n',
'django.template.context_processors.request',
'django.template.context_processors.media',
'django.template.context_processors.static',
'some_app_1.context_processors.very_heavy_cp_1',
'some_app_2.context_processors.very_heavy_cp_2',
'some_app_3.context_processors.very_heavy_cp_3',
],
'debug': True,
},
},
# Light engine - only very necessary things go here
{
'NAME': 'light',
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.i18n',
'django.template.context_processors.request',
'django.template.context_processors.media',
'django.template.context_processors.static',
],
'debug': True,
},
},
]
some_app_1.views.py
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.views.generic import View, TemplateView
Sample light view:
class TestLightView(View):
"""Test light view."""
template_name = 'some_app_1/test_light_view.html'
def get(self, request):
context = {}
response = render_to_response(
self.template_name,
context,
context_instance=RequestContext(request),
using='light' # Note, that we use `light` engine here
)
return response
Sample normal (heavy) view:
class TestNormalView(View):
"""Test normal view."""
template_name = 'some_app_1/test_normal_view.html'
def get(self, request):
context = {}
response = render_to_response(
self.template_name,
context,
context_instance=RequestContext(request),
using='default' # Note, that we use `default` engine here
)
return response
If you use TemplateView
, define template_engine
property.
Sample light view:
class TestTemplateLightView(TemplateView):
"""Test template light view"""
template_engine = 'light' # Note, that we use `light` engine here
# Your code goes here
Sample normal (heavy) view:
class TestTemplateNormalView(TemplateView):
"""Test template normal view."""
template_engine = 'default' # Note, that we use `default` engine here
# Your code goes here
Upvotes: 2
Reputation: 28846
This is what Django's lazy objects are for. Rather than calculate the actual contents in the context processor, you provide a lazy object with an associated function; when something actually tries to use the object, e.g. in a template, then it calls the function. This answer gives an example for the same problem.
Be careful about memoization if you use the variable more than once; some of the options will re-call the function, while some will save the result. You can look at the source to be sure. I think SimpleLazyObject
(as in the answer above) does what you want, but I haven't used this recently enough to be sure.
(An answer by request....)
Upvotes: 5
Reputation: 171
It might be easier to re-engineer your app so that some views make this query, while others do not. You can avoid this causing a lot of duplication by writing a "class-based view" that makes this particular database query and adds it to the context, and then inheriting it whenever you want a new view to make that extra query. I'd advocate for this approach instead of the global context processor.
This example shows how you could add something to the default template context.
Upvotes: 2
Reputation: 122476
You could subclass RequestContext
in django.template.context
and redefine its __init__
method. You can then use this modified RequestContext
in those particular views. The __init__
of RequestContext
currently looks like this:
def __init__(self, request, dict=None, processors=None, current_app=None, use_l10n=None): Context.__init__(self, dict, current_app=current_app, use_l10n=use_l10n) if processors is None: processors = () else: processors = tuple(processors) for processor in get_standard_processors() + processors: self.update(processor(request))
In here, get_standard_processors()
returns the context processors defined in your settings. Before calling a context processor (last line of the above code), you could add a check that determines which processors need to be used and which ones need to be skipped.
Upvotes: 2