I have a common data {the logged-in user's message number) to display on every page. I can simply pass to template as
dict={'messagenumber':5}
return render_to_response('template.html',dict,context_instance=RequestContext(request))
But it looks tedious if i have this dict data pass to very page. Is there an easier way to pass common data to every page?
Thanks
Just to save someone's time if new to django
settings.py
TEMPLATE_CONTEXT_PROCESSORS = ("django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.static",
"django.contrib.messages.context_processors.messages",
"home.context_processor.remote_ip")
in home application, create a python file called context_processor.py
in the context_processor.py add a function like this:
def remote_ip(request):
return {'remote_ip': request.META['REMOTE_ADDR']}
use it in the templates like {{ remote_ip }}
It blows me away how common this is. You want to use context processors my friend!
Very easy to create, like so:
def messagenumber_processor(request):
return {'messagenumber': 5}
Since messagenumber is a dynamic variable based on the User, you could pull data from the database by fetching from request.user as you have full access to request within each context processor.
Then, add that to your TEMPLATE_CONTEXT_PROCESSORS within settings.py and you're all set :-) You can do any form of database operation or other logic within the context processor as well, try it out!
Write your own function to handle it.
def render_with_message_number(template, message_number, request):
return render_to_response(template, dict(messagenumber=message_number),
context_instance=RequestContext(request))
And don't shadow dict.
Related
I have the following function that I call in all of my apps and in almost every view function.
def get_customer(request):
return request.user.customer
I want to have one function that I can call from every app or even have this value available in every view.
How can I do this?
I am not really sure how you want to use, but if you need something reusable mostly for templates (as views handle logic differently depending on the request) then you can proceed with the bellow method, if you need something reusable in different parts of the stack, then a simple function / class that is imported in the appropriate parts is just enough.
If you want to inject a reusable var inside the view, then a context.processor is the good place to have this kind of logic.
create a context_processors.py file (name does not matter, but it's always nice to follow Django naming schemes for readability) in one of your apps (most likely the app that deals mostly with the logic, probably the customer app).
In your context_processors.py:
def get_customer(request):
try:
customer = request.user.customer
return {'customer': customer}
except:
"""
You need to always return a dictionary, even empty.
"""
return {}
Enable the context processor, in your TEMPLATE_CONTEXT_PROCESSORS (settings.py):
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contry.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.static",
"django.core.context_processors.tz",
"django.contrib.messages.context_processors.messages"
"yourapp.context_processors.get_customer"
)
THen in your template you can access this:
{% if customer %}
...
{% endif %}
Mind though that is wise to create names that wont conflict with other parts, so it would be better to name the passed element
to something more unique like myappscustomer.
If you are using CBV's (Class Based Views) you could create a Mixin and reuse it:
class MyCustomerMixin(object):
def get_context_data(self, **kwargs):
context = super(MyCustomerMixin, self).get_context_data(**kwargs)
if self.request.user:
try:
context['mycustomer'] = self.request.user.customer
except:
pass
return context
Then use it in your View:
class SomeView(MyCustomerMixin, TemplateView):
....
Following the docs
If TEMPLATE_CONTEXT_PROCESSORS contains this processor, every
RequestContext will contain these variables:
user – An auth.User instance representing the currently logged-in user
(or an AnonymousUser instance, if the client isn’t logged in). perms –
An instance of django.contrib.auth.context_processors.PermWrapper,
representing the permissions that the currently logged-in user has.
I added these lines to settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
)
Rendering my templates as follows
def profile_view(request):
return render_to_response('profile.html', { 'profile' : 1 })
I was under the impression that the request context along with the user will be passed automatically. Is that not the case, or should i explicitly add context_instance=template.RequestContext(request)) to every view ?
Thanks.
Yes, if you want to use render_to_response and you want template context data available, you should pass in a RequestContext instance.
Alternatively, if you render your page with django.shortcuts.render, the RequestContext will be injected automatically.
You may find this answer useful, too: Django - what is the difference between render(), render_to_response() and direct_to_template()?
Is there any solution for setting some variables accessible in all templates without setting parameters in each views?
For example, if I login the system, the var = 1, and all templates can use var value.
(pre note: it is a good practice to always use these RequestContexts even if you don't need global data YET, because you never know if, upon a change, you will need global data later).
Use a Template Context Processor and use RequestContexts for each of your templates when you return from your views. When you send a RequestContext(request) as context for your templates inside your views, they will have all the data provided for each registered Context Processor.
e.g. consider this view:
def some_view(request):
# ...
c = RequestContext(request, {
'foo': 'bar',
}, [ip_address_processor])
return HttpResponse(t.render(c)) #or use render_to_resonse('yourtemplate', c)
if you had a context processor like:
def foos(request):
return {'var': 1} #this is the data this CP provides to each of your requests.
#yes, data must be a dict-like object.
you will have var as a variable in every request, in every template using RequestContext(request). Your prev. view would have both foo and var variables available (passing a dict-like argument as the second parameter for RequestContext is like passing that value directly to the render method or the render_to_response shortcut function; using the RequestContext(request, data) let's you enjoy all the data provided by your context processors).
If you use Django's Class-based views or the render() shortcut (and not the render_to_response shortcut), a RequestContext instance will automatically be used as the context.
REMEMBER that you must APPEND to the default values, instead of overriding the tuple. e.g.:
TEMPLATE_CONTEXT_PROCESSORS = ("django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.static",
"django.core.context_processors.tz",
"django.contrib.messages.context_processors.messages",
"path.to.foos")
in your settings.py file (all but the last, are the default context processors used in django 1.5). Otherwise you'd be losing most of the required CPs by the django core or many packages (yes, IMHO an ugly caveat, but if you override you must specify the default ones as well)
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",
)