I am trying to create a custom context processor which will render a list of menu items for a logged in user. I have done the following:
Within my settings.py I have
TEMPLATE_CONTEXT_PROCESSOR = (
'django.contrib.auth.context_processors.auth',
'mysite.accounts.context_processors.user_menu',
)
Under the accounts submodule I have context_processors.py with the following, for now:
def user_menu(request):
return {'user_menu':'Hello World'}
On my template page I have the following:
{% if user.is_authenticated %}
Menu
{{user_menu}}
{% endif %}
The invoking view is as follows:
def profile(request):
return render_to_response('accounts/profile.html',context_instance=RequestContext(request))
However I am unable to get the {{user_menu}} to render anything on the page, I know the user is authenticated as other sections of the template with similar checks render correctly. Am I missing something here. Please help
Thank you
Edit: Thanks Ben, Daniel, I have fixed the (S) in TEMPLATE_CONTEXT_PROCESSOR, however Django now has trouble resolving the module and I get the following message
Error importing request processor module django.contrib.auth.context_processors: "No module named context_processors"
UPDATE: I fixed it by changing the path to django.core.context_processors.auth Seems like the modules have been moved around
The setting name should be TEMPLATE_CONTEXT_PROCESSORS, with an S.
Related
My intention is to change from interface view -> switch view to process some data and send those data and change to -> test view to display the result. However, nothing in switch view seems to be processed and switch view doesn't change to test view after I hit 'submit' on userInterface.html. My guess is that the problem lies on the HttpResponseRedirect() function or anything related to url paths. Everything worked find with my other project that I worked on my computer. I'm not sure what I need to change to use Django on RaspberryPi.
At first, I found out I didn't import libraries needed for those function. After I imported them, the code was still not working.
I commented out other codes in switch view that do nothing with changing views and just focus on changing view in my switch view.
view.py
def user_interface(request):
return render(request,'zuumcoin/userInterface.html',
{})
def switch(request):
return HttpResponseRedirect(reverse('zuumcoin:test'))
def test(request):
return render(request,'zuumcoin/test.html',{})
userInterface.html
....
<form action="{% url 'zuumcoin:swicht' %} method = "POST">
{% csrf_token %}
...
...
</form>
urls.py
app_name='zuumcoin'
urlpatterns = [
url(r'', views.user_interface, name='interface'),
url(r'switch/', views.switch, name='switch'),
url(r'test/', views.test, name='test')
]
I expect HttpResponseRedirect to direct me to test view instead of being stuck in switch view. If it can do that, I think I can find a way for other part of my code in my switch view to run.
You didn't terminate your regexes. So the first pattern matches every path.
You should do:
url(r'^$', views.user_interface...)
It seems you have typo in your userInterface.html template. change this:
{% url 'zuumcoin:swicht' %}
to this one:
{% url 'zuumcoin:switch' %}
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',
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.
I learned how to authenticate users in Django months ago, but I've since upgraded and am having some problems so it occurred to me this morning that I may not have been doing it correctly from the start so I decided to ask.
In my project's urls.py file I've got ^accounts/login/$ and ^accounts/logout/$ both wired up to the built-in login() and logout() views (at django.contrib.auth.views) and ^accounts/profile/$ is connected to a view I've written, called "start_here" whose contents are basically this:
def start_here(request):
if request.user:
user_obj = request.user
else:
user_obj = None
is_auth = False
if request.user.is_authenticated():
is_auth = True
return render_to_response("profile.html", {'auth': is_auth,'user': user_obj,})
Now, "profile.html" extends a master template, called master.html, inside which is a "navbar" block whose contents are supposed to change if 'auth' == True (snippet below)
{% block navbar %}
{% if auth %}
Link A
Link B
Link C
Link D
Link E
Link F
Logout
{% else %}
Login
{% endif %}
{% endblock %}
My problem is that when I log in, and it redirects to /accounts/profile, the navbar doesn't display Links A-F + Logout, it displays only "login". It doesn't work the way I expect it to unless I manually copy-paste the above block into profile.html. When calling render_to_response(), does the context I provide get passed to the parent template as well as the child?
Full source to master and profile.html: http://dpaste.com/hold/128784/
I don't see anything suspect in the code.
This answer is tangential, but Jim's suggestion to use RequestContext is so good I want to explicitly explain how to do it.
You can reduce your start_here function to
from django.template import RequestContext
def start_here(request):
return render_to_response("profile.html", {},
context_instance=RequestContext(request))
By using RequestContext, user is automatically added to the context. Instead of using
{% if auth %}
use
{% if user.is_authenticated %}
Yes the context you pass in render_to_response() is passed to the named templates and ALL the templates it includes or inherits from.
You should look into Using RequestContext
Another thing to check...
Just making sure:
your profile template begins with
{% extends 'master.html' %}
In order to make sure django correctly identifies users, you need to make sure it is properly enabled in your settings module. specifically, you need to make sure that the SessionMiddleware and AuthenticationMiddleware modules are enabled in your settings.MIDDLEWARE_CLASSES. also be sure that auth is in your installed apps and you have run syncdb since enabling it.
If you have not taken the above steps, then django will not be able to detect when users have logged in and perform request setup properly.
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'}