I have a django project, with a lot of applications. Now i need to add some variables to the context dictionary only for some applications.Does django provide any option to achieve this?
I know decorator can be helpful.Is there any other way,like a middleware / context processor that runs automatically but only for specific applications.
A context processor like this can do what you need:
from django.core.urlresolvers import resolve
def app_var(request):
if resolve(request.path).app_name == 'YOUR_APP_NAME':
return {'CUSTOM_VAR': 'VALUE'}
return {}
to install the context processor, put the code in any file you like, and add a entry referencing (e.g. 'folder.file.app_var') it in the CONTEXT_PROCESSORS in your settings.py.
Related
Just looking for some guidance here on how to implement this concept in "Django fashion".
I am using dbsettings to define site level variables. On each request I want to check one of my site level variables and render a different response based on the value of that variable.
Now I realize I could easily accomplish this just by adding a simple if statement in each of my view functions, but I thought there may be a way I could apply this at a higher level?
Let me know if there is a way to "globalize" this functionality across all requests. Thanks.
Actually, what you really probably want is middleware, if the setting is going to affect the template that's chosen in the first place, or substantially affect the response. It is a good deal more flexible than using a template context processor, which is more appropriate if you simply want to add a couple variables to your context.
You create a middleware.py in your app, which might contain something like:
from django.conf import settings
class MyMiddleware(object):
def process_request(self, request):
request.my_app_setting = settings.MY_APP_SETTING
Don't forget to add your class to your MIDDLEWARE_CLASSES setting.
You can use custom template context processors for passing "global" context to your views.
To accomplish this, create a new contextprocessors.py somewhere in your application with code similar to the example below (all it has to do is return a dict). Then add the path to the file with the function in the TEMPLATE_CONTEXT_PROCESSORS tuple in your settings.py (ie: yourapp.contextprocessors.resource_urls).
from django.conf import settings
def resource_urls(request):
"""Passes global values to templates."""
return dict(
TIME_ZONE = settings.TIME_ZONE,
)
Now you can refer to these keys in your templates as expected: {{ TIME_ZONE }}.
I need to get an environment variable (ex: Mixpanel_Token) in all my templates, and without creating a new view in Django.
From what I read on SO, I should use a Template Context Processor.
The context_processor is defined in context_processors.py file:
from django.conf import settings
def settings_mixpanel(request):
ctx = {
"MIXPANEL_TOKEN": settings.MIXPANEL_TOKEN,
}
return ctx
In my settings.py file:
TEMPLATE_CONTEXT_PROCESSORS = (
'utils.context_processors.settings_mixpanel',
)
The issue I encounter is how to define MIXPANEL_TOKEN as a context variable in all my templates, given that all my views are already created in Django.
I don't want to recreate a view like the below one, using render_to_response function:
def index(request):
return render_to_response("index.html", {},context_instance=RequestContext(request))
You don't need to do anything special. As long as your template is rendered with RequestContext, you'll be able to access your variable with {{ MIXPANEL_TOKEN }}.
It is quite easy and straightforward: the context processors are called by RequestContext(...). If you do not use RequestContext(...), the context processors will not be used and will therefore not be of any value. You do not necessarily need to use render_to_response, but RequestContext is a must. Like it or not, that is how Django works. But from my personal view, changing your existing views to use RequestContext is not really a big thing, is it?
since Django 1.8 registring of custom context processor for templates happens via: TEMPLATES-> OPTIONS -> context_processors see here for reference: https://docs.djangoproject.com/en/1.10/ref/templates/upgrading/#the-templates-settings
I would like to write a context processor which will look the existing context, and if there is a form present, check that the user has permission to edit that object. If not, I will overwrite that context variable.
How do I read the existing context from inside a context processor?
Edit:
The reason for using this type of context processor is to avoid having the check permissions with if statements in each view. Some users will have read/write access, others will have read-only and others will have no access, at the object level. I would like to manipulate the form accordingly after the view has been processed.
Why not just wrap the view with a user_passes_test decorator? You can run any checks you like there -- no hacks required.
You should use django-authority, or any authority package. Although, I cannot guarantee that they don't rely on hacks themselves, but at least you wouldn't be alone using the hacks. That said, here is a working solution to your issue:
Monkey patch django.template.base.RequestContext, to set request.context = self.
Create a template context processor, which can use request.context
Add the context processor to settings, and you're good to go
Here is an example, which you can just paste in settings.py, it works:
def print_context(request):
print request.context.get('form', 'No form in this context')
return {}
from django.template.base import RequestContext
orig_init = RequestContext.__init__
def new_init(self, request, **kwargs):
request.context = self
orig_init(self, request, **kwargs)
RequestContext.__init__ = new_init
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.request',
'settings.print_context',
)
Note that you are working against Django's design, I posted this answer assuming you know what you're doing - you know both Python and Django very well.
I have a few views and they all work good and all use templates that extend one base template that outputs the core HTML, the header, footer, navigation and so on. Happy family.
now, I want to play with sessions on the pages and since you can't get access to user's session information from the template without actually passing it from the view (correct me where I'm wrong) I have two options:
add session data to the rest of the bits I pass as context to HTML templates in views (not sure if this is a good way to go)
somehow inherit all existing views from a view that will be always pushing context to templates being processed - this way I don't have to worry about anything else I may want to add to my pages in the future - is this possible?
I'm very new to django and there may be other proper way of doing this - all your suggestions are much appreciated.
I think adding in a context processor is a very easy way to do this.
You could either write your own or use this one:
DJANGO.CORE.CONTEXT_PROCESSORS.REQUEST
http://docs.djangoproject.com/en/dev/ref/templates/api/#django-core-context-processors-request
Then you will have the request in your template, and could get to the session with request.session
If you do that though, make sure that you pass the RequestContext along in your views to the templates, something like this:
from django.template import RequestContext
def some_view(request):
# ...
return render_to_response('my_template.html',
my_data_dictionary,
context_instance=RequestContext(request))
Also modify your settings.py to add in the context processor
TEMPLATE_CONTEXT_PROCESSORS = DEFAULT_SETTINGS.TEMPLATE_CONTEXT_PROCESSORS + (
"django.core.context_processors.request",
)
I'm trying to find a way to cache the results of a query that won't change with frequency. For example, categories of products from an e-commerce (cellphones, TV, etc).
I'm thinking of using the template fragment caching, but in this fragment, I will iterate over a list of these categories. This list is avaliable in any part of the site, so it's in my base.html file. Do I have always to send the list of categories when rendering the templates? Or is there a more dynamic way to do this, making the list always available in the template?
Pop your cached query into Django's cache:
from django.core.cache import cache
cache.set('key', queryset)
Then create a context processor to add the value of the cache to all templates:
# myproject/myapp/context_processors.py
from django.core.cache import cache
def cached_queries():
return {'cache', cache.get('key')}
Then add your context processor in your Django settings file:
TEMPLATE_CONTEXT_PROCESSORS += (
'myproject.myapp.context_processors.cached_queries'
)
Now you will be able to access the cache variable in all generic templates and all templates which have a requests context, which a template is given if this is done in the view:
return render_to_response('my_template.html',
my_data_dictionary,
context_instance=RequestContext(request))
When to Set the Cache
It depends on what is contained in the cache. However a common problem is that Django only really gets to execute Python whenever a page request is sent, and this is often not where you want to do this kind of work.
An alternative is to create a custom management command for a particular app. You can then either run this manually when necessary, or more commonly set this to run as a cron job.
To create a management command you must create a class decended from Command inside of a management/commands directory located inside of an app:
# myproject/myapp/management/commands/update_cache.py
from django.core.management.base import NoArgsCommand
from django.core.cache import cache
class Command(NoArgsCommand):
help = 'Refreshes my cache'
def handle_noargs(self, **options):
cache.set('key', queryset)
The name of this file is important as this will be the name of the command. In this case you can now call this on the command line:
python manage.py update_cache
You can also use johnny-cache for automatic caching of querysets. It will (by default) cache all querysets, but you can force it not to cache some.