Context Processor for specific app only - python

'context_processors': [
...
...
"publicfront.views.context_processors.add_event_url"
],
I added this context processor in settings.py and want to use only for a specific app. How could I achieve this?

The context processor is run for all requests.
If you need to mimic the functionality you speak about, then you could add some if/else conditions in the context processor function, which gets the request object as first argument, so you may determine which app is running and populate the returned dict accordingly

Most of the answers I've found so far are about adding a context_processors into the site's settings.py. But I want my application to be an independent development unit. On deployment, I don't want to perform on the site unnecessary adjustments that I could've included into the distribution. As it was already hinted above (by Daniel Roseman), we can use custom tags (doc):
# file `extras.py`
from django.template.defaultfilters import register
import platform
CURRENT_OS = platform.system()
#register.simple_tag
def current_os():
return CURRENT_OS
That can be used like this:
{% load extras %}
. . .
<div>{% current_os %}</div>
As the request object is accessible in a template it may be processed with a custom filter (doc) like this:
# file `extras.py`
#register.filter
def my_filter(req):
return req.GET.get('q')
Usage:
<div>You searched for '{{ request|my_filter }}'.</div>

Related

Fetching a mobile or desktop template using django middleware [duplicate]

I want to write custom template loader for my Django app which looks for a specific folder based on a key that is part of the request.
Let me get into more details to be clear. Assume that I will be getting a key on every request(which I populate using a middleware).
Example: request.key could be 'india' or 'usa' or 'uk'.
I want my template loader to look for the template "templates/<key>/<template.html>". So when I say {% include "home.html" %}, I want the template loader to load "templates/india/home.html" or "templates/usa/home.html" or "templates/uk/home.html" based on the request.
Is there a way to pass the request object to a custom template loader?
I've been searching for the same solution and, after a couple days of searching, decided to use threading.local(). Simply make the request object global for the duration of the HTTP request processing! Commence rotten tomato throwing from the gallery.
Let me explain:
As of Django 1.8 (according to the development version docs) the "dirs" argument for all template finding functions will be deprecated. (ref)
This means that there are no arguments passed into a custom template loader other than the template name being requested and the list of template directories. If you want to access paramters in the request URL (or even the session information) you'll have to "reach out" into some other storage mechanism.
import threading
_local = threading.local()
class CustomMiddleware:
def process_request(self, request):
_local.request = request
def load_template_source(template_name, template_dirs=None):
if _local.request:
# Get the request URL and work your magic here!
pass
In my case it wasn't the request object (directly) I was after but rather what site (I'm developing a SaaS solution) the template should be rendered for.
To find the template to render Django uses the get_template method which only gets the template_name and optional dirs argument. So you cannot really pass the request there.
However, if you customize your render_to_response function to pass along a dirs argument you should be able to do it.
For example (assuming you are using a RequestContext as most people would):
from django import shortcuts
from django.conf import settings
def render_to_response(template_name, dictionary=None, context_instance=None, content_type=None, dirs):
assert context_instance, 'This method requires a `RequestContext` instance to function'
if not dirs:
dirs = []
dirs.append(os.path.join(settings.BASE_TEMPLATE_DIR, context_instance['request'].key)
return shortcuts.render_to_response(template_name, dictionary, context_instance, content_type, dirs)

How do I pass variables to all templates in django? [duplicate]

This question already has an answer here:
Django - How to make a variable available to all templates?
(1 answer)
Closed 6 years ago.
I am trying to pass variables (browser variable) to all my templates in my app. Any advice on how to get it to work?
View:
def browser(request):
primary_cat_list = Categories.objects.order_by("category")
subcat_list = SubCategories.objects.order_by("sub_category")
product = Productbackup.objects.order_by("website")
browser = list(chain(primary_cat_list, subcat_list, product))
return render_to_response('reserve/templates/base.html', locals(), context_instance=RequestContext(request))
Template:
{% for prod in browser %} {{ prod }}, {% endfor %}
You, my friend, are in the market for Context Processors.
From a blog entry written by a far nimbler and erudite technical writer than I:
What are template context processors?
Django’s context processors are a facility that allows you to provide data and callbacks to your templates.
You can do so in one of two ways:
On an individual request basis: by passing a custom Context value to your render_to_response() call
Globally: by creating a context processor method that accepts a HttpRequest object as input, and returns a payload or callback, then
registering the context processor in your settings.py, then providing your render_to_response() call with the built-in RequestContext attribute
instead of your own (you can always extend RequestContext to add more data on an individual request basis of course).
If that approach for passing data to templates sounded absurd and obfuscated to you, you’re not alone. The complexity involved in such a simple operation is unwarranted and counter-productive, but every system has its shortcomings.
The official documentation is here:
https://docs.djangoproject.com/en/dev/ref/templates/api/
So but yeah, I have been programming with Django for a while, and one of the reasons I really like solving problems w/ it is because it is almost Byzantine in its complexity, but not in a domineering sort of way. It has a ton of geegaws and doodads that may not immediately appear useful; each of these either comes in extremely handy when you need it, and it will stay out of your way if not.
The upshot here for you is: context processors are a fine example of those. Yes.
Currently you're passing locals() as the variable scope which should include browser aswell, but I find the use of locals() very ugly.
Personally I always prefer a pattern like this instead:
def browser(request):
context = RequestContext(request)
primary_cat_list = Categories.objects.order_by("category")
subcat_list = SubCategories.objects.order_by("sub_category")
product = Productbackup.objects.order_by("website")
browser = list(chain(primary_cat_list, subcat_list, product))
context['browser'] = browser
return render_to_response('reserve/templates/base.html', context_instance=context)
I can give you an example of my code, that works fine. Here is the file named context_processors.py:
context_processors.py
def base(request):
user = request.user
#======================
#Login form
#=====================
# here is the code for login user or check if he is logged in already
return {
'user': user,
}
and that's, part of my base.html (a template that I use wor all my pages)
base.html
{% if user.username %}
<h3>
Welcome {{ user.username }}
</h3>

Defining Constants in Django

I want to have some constants in a Django Projects. For example, let's say a constant called MIN_TIME_TEST.
I would like to be able to access this constant in two places: from within my Python code, and from within any Templates.
What's the best way to go about doing this?
EDIT:
To clarify, I know about Template Context Processors and about just putting things in settings.py or some other file and just importing.
My question is, how do I combine the two approaches without violating the "Don't Repeat Yourself" rule? Based on the answers so far, here's my approach:
I'd like to create a file called global_constants.py, which will have a list of constants (things like MIN_TIME_TEST = 5). I can import this file into any module to get the constants.
But now, I want to create the context processor which returns all of these constants. How can I go about doing this automatically, without having to list them again in a dictionary, like in John Mee's answer?
Both Luper and Vladimir are correct imho but you'll need both in order to complete your requirements.
Although, the constants don't need to be in the settings.py, you could put them anywhere and import them from that place into your view/model/module code. I sometimes put them into the __init__.py if I don't care to have them to be considered globally relevant.
a context processor like this will ensure that selected variables are globally in the template scope
def settings(request):
"""
Put selected settings variables into the default template context
"""
from django.conf import settings
return {
'DOMAIN': settings.DOMAIN,
'GOOGLEMAPS_API_KEY': settings.GOOGLEMAPS_API_KEY,
}
But this might be overkill if you're new to django; perhaps you're just asking how to put variables into the template scope...?
from django.conf import settings
...
# do stuff with settings.MIN_TIME_TEST as you wish
render_to_response("the_template.html", {
"MIN_TIME_TEST": settings.MIN_TIME_TEST
}, context_instance=RequestContext(request)
To build on other people's answers, here's a simple way you'd implement this:
In your settings file:
GLOBAL_SETTINGS = {
'MIN_TIME_TEST': 'blah',
'RANDOM_GLOBAL_VAR': 'blah',
}
Then, building off of John Mee's context processor:
def settings(request):
"""
Put selected settings variables into the default template context
"""
from django.conf import settings
return settings.GLOBAL_SETTINGS
This will resolve the DRY issue.
Or, if you only plan to use the global settings occasionally and want to call them from within the view:
def view_func(request):
from django.conf import settings
# function code here
ctx = {} #context variables here
ctx.update(settings.GLOBAL_SETTINGS)
# whatever output you want here
Consider putting it into settings.py of your application. Of course, in order to use it in template you will need to make it available to template as any other usual variable.
Use context processors to have your constants available in all templates (settings.py is a nice place to define them as Vladimir said).
Context processors are better suited at handling more dynamic object data--they're defined as a mapping in the documentation and in many of the posts here they're being modified or passed around to views--it doesn't make sense that a template may lose access to global information because, for example, your forgot to use a specialized context processor in the view. The data is global by definition & that couples the view to the template.
A better way is to define a custom template tag. This way:
templates aren't relying on views to have global information passed into them
it's DRY-er: the app defining the global settings can be exported to many projects, eliminating common code across projects
templates decide whether they have access to the global information, not the view functions
In the example below I deal with your problem--loading in this MIN_TIME_TEST variable--and a problem I commonly face, loading in URLs that change when my environment changes.
I have 4 environments--2 dev and 2 production:
Dev: django-web server, url: localhost:8000
Dev: apache web server: url: sandbox.com -> resolves to 127.0.0.1
Prod sandbox server, url: sandbox.domain.com
Prod server: url: domain.com
I do this on all my projects & keep all the urls in a file, global_settings.py so it's accessible from code. I define a custom template tag {% site_url %} that can be (optionally) loaded into any template
I create an app called global_settings, and make sure it's included in my settings.INSTALLED_APPS tuple.
Django compiles templated text into nodes with a render() method that tells how the data should be displayed--I created an object that renders data by returnning values in my global_settings.py based on the name passed in.
It looks like this:
from django import template
import global_settings
class GlobalSettingNode(template.Node):
def __init__(self, settingname):
self.settingname = settingname;
def render(self, context):
if hasattr(global_settings, self.settingname):
return getattr(global_settings, self.settingname)
else:
raise template.TemplateSyntaxError('%s tag does not exist' % self.settingname)
Now, in global_settings.py I register a couple tags: site_url for my example and min_test_time for your example. This way, when {% min_time_test %} is invoked from a template, it'll call get_min_time_test which resolves to load in the value=5. In my example, {% site_url %} will do a name-based lookup so that I can keep all 4 URLs defined at once and choose which environment I'm using. This is more flexible for me than just using Django's built in settings.Debug=True/False flag.
from django import template
from templatenodes import GlobalSettingNode
register = template.Library()
MIN_TIME_TEST = 5
DEV_DJANGO_SITE_URL = 'http://localhost:8000/'
DEV_APACHE_SITE_URL = 'http://sandbox.com/'
PROD_SANDBOX_URL = 'http://sandbox.domain.com/'
PROD_URL = 'http://domain.com/'
CURRENT_ENVIRONMENT = 'DEV_DJANGO_SITE_URL'
def get_site_url(parser, token):
return GlobalSettingNode(CURRENT_ENVIRONMENT)
def get_min_time_test(parser, token):
return GlobalSettingNode('MIN_TIME_TEST')
register.tag('site_url', get_site_url)
register.tag('min_time_test', get_min_time_test)
Note that for this to work, django is expecting global_settings.py to be located in a python packaged called templatetags under your Django app. My Django app here is called global_settings, so my directory structure looks like:
/project-name/global_settings/templatetags/global_settings.py
etc.
Finally the template chooses whether to load in global settings or not, which is beneficial for performance. Add this line to your template to expose all the tags registered in global_settings.py:
{% load global_settings %}
Now, other projects that need MIN_TIME_TEST or these environments exposed can simply install this app =)
In the context processor you can use something like:
import settings
context = {}
for item in dir(settings):
#use some way to exclude __doc__, __name__, etc..
if item[0:2] != '__':
context[item] = getattr(settings, item)
Variant on John Mee's last part, with a little elaboration on the same idea Jordan Reiter discusses.
Suppose you have something in your settings akin to what Jordan suggested -- in other words, something like:
GLOBAL_SETTINGS = {
'SOME_CONST': 'thingy',
'SOME_OTHER_CONST': 'other_thingy',
}
Suppose further you already have a dictionary with some of the variables you'd like to pass your template, perhaps passed as arguments to your view. Let's call it my_dict. Suppose you want the values in my_dict to override those in the settings.GLOBAL_SETTINGS dictionary.
You might do something in your view like:
def my_view(request, *args, **kwargs)
from django.conf import settings
my_dict = some_kind_of_arg_parsing(*args,**kwargs)
tmp = settings.GLOBAL_SETTINGS.copy()
tmp.update(my_dict)
my_dict = tmp
render_to_response('the_template.html', my_dict, context_instance=RequestContext(request))
This lets you have the settings determined globally, available to your templates, and doesn't require you to manually type out each of them.
If you don't have any additional variables to pass the template, nor any need to override, you can just do:
render_to_response('the_template.html', settings.GLOBAL_SETTINGS, context_instance=RequestContext(request))
The main difference between what I'm discussing here & what Jordan has, is that for his, settings.GLOBAL_SETTINGS overrides anything it may have in common w/ your context dictionary, and with mine, my context dictionary overrides settings.GLOBAL_SETTINGS. YMMV.

Django: Template context processor request variable

I am trying to implement django-facebookconnect, for I need to check if a user logged in via Facebook or a regular user.
At the template, I can check if user logged in via facebook by checking request.facebook.uid
such as:
{% if is_facebook %}
{% show_facebook_photo user %}
{% endif %}
For this, I need to pass is_facebook': request.facebook.uid to the template and I will be using this in everywhere thus I want tried to apply it to an existing template context processor and call the snipplet above at the base.html, and it works fine for Foo objects:
def global_variables(request):
from django.conf import settings
from myproject.myapp.models import Foo
return {'is_facebook': request.facebook.uid,'foo_list': Foo.objects.all()}
I can list Foo objects at any view without any issue however it fails for this new is_facebook, it simply returns nothing.
If I pass 'is_facebook': request.facebook.uid in every single view , it works but I need this globally for any view rendering.
If you have access via the request object, why do you need to add a special is_facebook boolean at all? Just enable the built-in django.core.context_processors.request and this will ensure that request is present in all templates, then you can do this:
{% if request.facebook.uid %}
It could be a timing issue. Make sure that the Common middleware comes before the facebook middleware in your settings file. You can probably debug and see when the facebook middleware is modifying the request and when your context processor is invoked. That may give you some clue as to why this is happening. But, as Daniel said, you can always just use the request object in your templates.

Always including the user in the django template context

I am working on a small intranet site for a small company, where user should be able to post. I have imagined a very simple authentication mechanism where people just enter their email address, and gets sent a unique login url, that sets a cookie that will always identify them for future requests.
In my template setup, I have base.html, and the other pages extend this. I want to show logged in or register button in the base.html, but how can I ensure that the necessary variables are always a part of the context? It seems that each view just sets up the context as they like, and there is no global context population. Is there a way of doing this without including the user in each context creation?
Or will I have to make my own custom shortcuts to setup the context properly?
There is no need to write a context processor for the user object if you already have the "django.core.context_processors.auth" in TEMPLATE_CONTEXT_PROCESSORS and if you're using RequestContext in your views.
if you are using django 1.4 or latest the module has been moved to django.contrib.auth.context_processors.auth
#Ryan: Documentation about preprocessors is a bit small
#Staale: Adding user to the Context every time one is calling the template in view, DRY
Solution is to use a preprocessor
A: In your settings add
TEMPLATE_CONTEXT_PROCESSORS = (
'myapp.processor_file_name.user',
)
B: In myapp/processor_file_name.py insert
def user(request):
if hasattr(request, 'user'):
return {'user':request.user }
return {}
From now on you're able to use user object functionalities in your templates.
{{ user.get_full_name }}
In a more general sense of not having to explicitly set variables in each view, it sounds like you want to look at writing your own context processor.
From the docs:
A context processor has a very simple interface: It's just a Python function that takes one argument, an HttpRequest object, and returns a dictionary that gets added to the template context. Each context processor must return a dictionary.
The hints are in every answer, but once again, from "scratch", for newbies:
authentication data is in templates (almost) by default -- with a small trick:
in views.py:
from django.template import RequestContext
...
def index(request):
return render_to_response('index.html',
{'var': 'value'},
context_instance=RequestContext(request))
in index.html:
...
Hi, {{ user.username }}
var: {{ value }}
...
From here: https://docs.djangoproject.com/en/1.4/topics/auth/#authentication-data-in-templates
This template context variable is not available if a RequestContext is
not being used.
#Dave
To use {{user.username}} in my templates, I will then have to use
requestcontext rather than just a normal map/hash: http://www.djangoproject.com/documentation/templates_python/#subclassing-context-requestcontext
So I guess there are no globals that the template engine checks.
But the RequestContext has some prepopulate classes that I can look into to solve my problems. Thanks.
If you can hook your authentication into the Django authentication scheme you'll be able to use request.user.
I think this should just be a case of calling authenticate() and login() based on the contents of your Cookie.
Edit: #Staale - I always use the locals() trick for my context so all my templates can see request and so request.user. If you're not then I guess it wouldn't be so straightforward.
its possible by default, by doing the following steps, ensure you have added the context 'django.contrib.auth.context_processors.auth' in your settings. By default its added in settings.py, so its looks like this
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.auth',)
And you can access user object like this,
{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{% else %}
<p>Welcome, new user. Please log in.</p>
{% endif %}
For more information, refer here http://docs.djangoproject.com/en/1.2/topics/auth/#authentication-data-in-templates
Use context_processors. https://docs.djangoproject.com/en/2.2/ref/settings/#std:setting-TEMPLATES-OPTIONS
settings.py
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'myapp.functions.test'
],
},
myapp/functions.py
def test(request):
return {'misc': 'misc'}

Categories