Context processors in Django usually allow for a variable to be accessed by all templates. How do I access this variable in the views.py (backend) code?
Here is what I have tried:
def index(request):
request_context = RequestContext(request)
center = request_context.get("center")
But I get "none" for the center variable.
And in the context processor code:
def center(request):
return {'center': '123'}
I have added the context processor's "center" function to the context processor list in settings.
Use decorators instead of context_processors. It will be really very simple for you.
In views.py use #csrf_exempt before function from which you want to take a variable and use {% csrf_token %} on the end of a line in the template where you want to use that variable.
Official documentation on csrf decorators
If you need to see an example then check out this. Here in template/add_comment.html and views.py is using decorators.
NOTE:- you need to import csrf_exempt in views.py before using it like:-
from django.views.decorators.csrf import csrf_exempt
Related
base.html is used as the base template for all other pages. base.html has the navigation bar and in the navigation bar, I want to show the number of messages the user received. Thus, I need to have a variable like {{number_of_messages}} in the base.html.
However, how should I pass this variable to it? Every template extends base.html and is rendered by a function. I don't think returning number_of_messages in all functions is a good way. Is there better way to implement this? How can I pass this variable to all templates?
You can use tags.
#myproject/myproject/templatetags/tags.py
from django import template
register = template.Library()
#register.simple_tag
def number_of_messages(request):
return _number
In your Base.html
{% load tags %}
{% number_of_messages request %}
Have a look at:
https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.RequestContext
As long as:
you use the render shortcut in your view (or otherwise take care to use a RequestContext to render your response)
have django.contrib.auth.context_processors.auth in your TEMPLATE_CONTEXT_PROCESSORS setting (as it is by default)
...then you have the current request's User (or AnonymousUser) instance available in your template as {{ user }} ...I am guessing from there you may be able to access the number of messages directly?
Or perhaps you are using Django's messages framework?
This comes with it's own context processor which (as long as you use render or RequestContext) will make a {{ messages }} var (containing the messages for current user) available in your templates. For 'number of messages' you can do {{ messages|length }}
If none of these built-in options provide what you need you can either:
make your own template context processor which will run for every request and make additional variables available to all templates (when rendered with a RequestContext)
make your own template tag which can be used only where needed... of course if this is used in your base.html and all templates inherit from base.html then it's still going to run for every page.
I find the simplest steps to passing variables to your base templates in django is to add a context_processor.py file like so:
In your app create context_processors.py and declare your variables e.g.:
# context_processors.py
def message_processor(request):
if request.user.is_authenticated:
no_msgs = request.user.profile.msgs
else:
no_msgs = 0
return {
'messages' : no_msgs
}
Then register your process or under TEMPLATES in your settings.py file:
TEMPLATES = [
{
...
'context_processors': [
...
# custom
'appname.context_processors.message_processor',
],
},
},
]
And then you will be able to get that variable anywhere in your app as:
{{ messages }}
If you want the variable in really all the views, then a custom template context processor is probably the best option.
https://docs.djangoproject.com/en/dev/ref/templates/api/#subclassing-context-requestcontext
If you want the variable only in some of the views, then you can make those views call a common function that populates the common variables, something like this:
def some_view(request):
params = _common_params(request)
params.update({
# params specific to .some_view
})
return render_to_response('path/to/template, params)
or create a custom decorator like this:
from functools import wraps
def render_with_params():
def _inner(view_method):
def _decorator(request, *args, **kwargs):
params = _common_params(request)
(template_path, view_params) = view_method(request, *args, **kwargs)
params.update(view_params)
return render_to_response(template_path, params, context_instance=RequestContext(request))
return wraps(view_method)(_decorator)
return _inner
#render_with_params()
def some_view(request):
params = { ... }
return ('path/to/template', params)
I am trying to learn Django. I am creating a small applicationt to understand its basic functionalities. In views.py of a django app, some tutorials use render() from template while others use render() from django shortcuts module.
For instance, in views.py
from django.shortcuts import render
def home(request):
context = {}
template = "app/add_item.html"
return render(request, template,context)
and yet others,
from django.http.response import HttpResponse
from app.models import Items # this is the model
def home(request):
item_list = Items.objects.order_by('-item_name')
template = loader.get_template('app/add_item.html') # could be index.html as well
context = {
'item_list': item_list,
}
return HttpResponse(template.render(context, request))
What is the difference between render() method of DjangoTemplates class and render() method found in django.shortcuts module? Which one should I prefer and why?
django.shortcuts.render is, as its name implies, a shortcut for returning a rendered template as a response from a view. Its use is rather limited to that context. It takes an HttpRequest instance as its first argument and its main purpose, per the docs, is to
combine a given template with a given context dictionary and returns an HttpResponse object with that rendered text.
Importantly, this selects a template by name. It is intended to select a template for rendering and returning as a response.
Template.render is part of the low-level template API and takes the single template, represented by that object, and renders it to a string.
Importantly, this takes only the template already represented by your object. It has no mechanism for discovering another template to render.
Generally, the shortcut version is the most useful, as quite often you want to return a rendered template as a response from your views. This is the whole reason it exists.
Is there a way to call all my user data? without using all the template variables in my views
Templates:
{% csrf_token %}
<h1>Welcome {{user.full_name}} {{user.last_name}}</h1>
<h1>{{user.email}}</h1>
so in my views I'll use less code, by not declaring all the dict
views
return render_to_response('user/userhome.html', user)
For django version 1.8 or more you can directly access {{user}} in template. However you can add the following in the TEMPLATE_CONTEXT_PROCESSOR of your settings to access {{user}} directly in the template.
'django.contrib.auth.context_processors.auth',
You can use a dict-like object that defines __contains__ and __getitem__, but uses attribute access to set properties, eg.:
from django import shortcuts, template
from django.contrib.auth.decorators import login_required
class Page(dict):
# see http://stackoverflow.com/questions/4984647/accessing-dict-keys-like-an-attribute-in-python
def __init__(self, *args, **kwargs):
super(Page, self).__init__(*args, **kwargs)
self.__dict__ = self
#login_required
def foo(request):
page = Page()
page.user = request.user
return shortcuts.render_to_response('foo.html', page)
then you can write your template exactly the way you would like.
This is simplified code example, but may be someone knows the reason the problem occurs without the exact copy of the code. So:
class FooView(TemplateView):
template_name = 'foo.html'
def get_context_data(self, **kwargs)
context = super(FooView, self).get_context_data(**kwargs)
...
# here we get link to domain
...
args = {'domain': domain}
context.update(args)
import pdb; pdb.set_trace() # here 'domain' has a value
return context
The html template foo.html tries to access the 'domain' value with {{ domain }}, but it is None.
This happens only if I use 'domain' as the label. So if I change domain to domain1 or foo - it works.
How is this possible? Is it possible domain name gots overwritten somehow, maybe some has a clue?
EDIT Change get_context_view --> get_context_data (mistype)
EDIT2 My 'domain' context variable gets ovewritten by context_processor. All worked fine when function-based views were used. After switching to class-based views - the 'domain' started to get overwritten. May be get_context_data() is not strong enough? Is there any way to prevent context processor from overwriting the variable?
Yes, it is possible if some or template tags of context processors injects domain variable into context.
Are you sure than method is called get_context_view? Imho it should be get_context_data.
The TemplateView returns a TemplateResponse which is known to overwrite the context passed to it with data from context processors. This is something that's changing in Django 1.8 to be more consistent with render.
You should be able to fix this by overwriting render_to_response on your view with something like:
from django.shortcuts import render
...
class FooView(TemplateView):
def render_to_response(self, context, **response_kwargs):
return render(self.request, self.get_template_names()[0], context)
I receive this message:
CSRF token missing or incorrect.
In most forums, the tell you to get the {% csrf_token %} in the form, and i do have it.
Also i have in my settings.py:
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.csrf",
"django.contrib.auth.context_processors.auth",
)
I am using jinja, which didn't seem to use CSRF, but then i installed django registration and i got lost, since, it seems to be using some other views, that i don't have access to so to say, they are not written by me, and i can't figure out where they are. "standard auth views" as they call them. So i am unable to add "RequestContext".
Any ideas what's going on and how I can get it going? thanx
You might have to rewrite the django-registration view manually. Looks like there's an issue with how Jinja likes to do things and how Django wants to configure template loaders..
To look at the standard auth views, just look under "site-packages" in your python installation.
You could try wrapping the standard auth views like this:
from django.contrib.auth.views import login, logout
from django.views.decorators.csrf import csrf_protect
#csrf_protect
def my_wrapped_login_view(request):
return login(request)
#csrf_protect
def my_wrapped_logout_view(request):
return logout(request)
I basically imported Django's standard auth views and called them with my own, which have the csrf_protect decoration. It's worth a shot.
Have you also got the standard Django Templating system installed? That will be required for most apps that are distributed with templates.
For CSRF, a context processor inserts the variable 'csrf_token' into the response context that it retrieves from the middleware if enabled. Now all you have to do, is make sure that it's apart of your form.
This is straight out of django.core, and is subject to change at any time.
if csrf_token:
if csrf_token == 'NOTPROVIDED':
return mark_safe(u"")
else:
return mark_safe(u"<div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='%s' /></div>" % csrf_token)
However, seeing that, all you really need to know is that you have to have an input type named csrfmiddlewaretoken with the value of context.get('csrf_token','') within your form and that's all she wrote.
This answer isn't specific to django-registration, but just using Django with Jinja2 in general.
Django's CsrfViewMiddleware sets the csrf_token cookie if it determines that you have accessed the csrf_token context member. Unfortunately, Jinja2 rendering doesn't occur until after Django's middleware executes. As a result, the cookie doesn't get set, and therefore does not match the form, and you will get the 403 error.
To get around this issue, you need to access context['csrf_token'] at some point before you finish processing the response.
If you're using class-based views, you can create a CsrfProtectMixin:
class CsrfProtectMixin(object):
def render_to_response(self, context, **response_kwargs):
# Csrf processing happens when using a RequestContext.
# Be sure to use one.
if not isinstance(context, RequestContext):
context = RequestContext(self.request, context)
# Force access to csrf_token due to the way jinja2 renders the template
# after middleware has finished processing. Otherwise, the csrf cookie
# will not be set.
str(context.get('csrf_token'))
return super(CsrfProtectMixin, self).render_to_response(context, **response_kwargs)
And then in your view class:
class MyView(CsrfProtectMixin, TemplateView):
def get(self, request, *args, **kwargs):
context = {}
return self.render_to_response(context)
If you're not using class-based views, you can do something like:
def my_view(request):
context = RequestContext(request)
str(context['csrf_token']) #force access to the csrf_token
return render_to_response('template.html', context)
Or perhaps monkey patch render_to_reponse with the logic in the class, above.
The most straightforward answer to this one is to just put {% csrf_token %} within the form tag in your template/html.
I just switched off the csrf middleware in the settings like so, and now it works:
#'django.middleware.csrf.CsrfViewMiddleware',