简体   繁体   中英

Django, exclude a context processor in a view

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,

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, eg 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....)

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.

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.

That's very easy to achieve using various template engines.

1. Define alternative (light) template engine in your project settings

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,
        },
    },
]

2. How to use light engine in your views

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM