User authentication in Django - python

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.

Related

Codes in one of my views are not processed when I access to that view

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' %}

Django pass render_to_response template in other template

this is probably a question for absolute beginners since i'm fairly new to progrmaming. I've searched for couple of hours for an adequate solution, i don't know what else to do.
Following problem. I want to have a view that displays. e.g. the 5 latest entries & 5 newest to my database (just an example)
#views.py
import core.models as coremodels
class LandingView(TemplateView):
template_name = "base/index.html"
def index_filtered(request):
last_ones = coremodels.Startup.objects.all().order_by('-id')[:5]
first_ones = coremodels.Startup.objects.all().order_by('id')[:5]
return render_to_response("base/index.html",
{'last_ones': last_ones, 'first_ones' : first_ones})
Index.html shows the HTML content but not the content of the loop
#index.html
<div class="col-md-6">
<p> Chosen Items negative:</p>
{% for startup in last_ones %}
<li><p>{{ startup.title }}</p></li>
{% endfor %}
</div>
<div class="col-md-6">
<p> Chosen Items positive:</p>
{% for startup in first_ones %}
<li><p>{{ startup.title }}</p></li>
{% endfor %}
Here my problem:
How can I get the for loop to render the specific content?
I think Django show render_to_response in template comes very close to my problem, but i don't see a valid solution there.
Thank you for your help.
Chris
--
I edited my code and problem description based on the solutions provided in this thread
the call render_to_response("base/showlatest.html"... renders base/showlatest.html, not index.html.
The view responsible for rendering index.html should pass all data (last_ones and first_ones) to it.
Once you have included the template into index.html
{% include /base/showlatest.html %}
Change the view above (or create a new one or modify the existing, changing urls.py accordingly) to pass the data to it
return render_to_response("index.html",
{'last_ones': last_ones, 'first_ones' : first_ones})
The concept is that the view renders a certain template (index.html), which becomes the html page returned to the client browser.
That one is the template that should receive a certain context (data), so that it can include other reusable pieces (e.g. showlatest.html) and render them correctly.
The include command just copies the content of the specified template (showlatest.html) within the present one (index.html), as if it were typed in and part of it.
So you need to call render_to_response and pass it your data (last_ones and first_ones) in every view that is responsible for rendering a template that includes showlatest.html
Sorry for the twisted wording, some things are easier done than explained.
:)
UPDATE
Your last edit clarified you are using CBV's (Class Based Views).
Then your view should be something along the line:
class LandingView(TemplateView):
template_name = "base/index.html"
def get_context_data(self, **kwargs):
context = super(LandingView, self).get_context_data(**kwargs)
context['last_ones'] = coremodels.Startup.objects.all().order_by('-id')[:5]
context['first_ones'] = coremodels.Startup.objects.all().order_by('id')[:5]
return context
Note: personally I would avoid relying on the id set by the DB to order the records.
Instead, if you can alter the model, add a field to mark when it was created. For example
class Startup(models.Model):
...
created_on = models.DateTimeField(auto_now_add=True, editable=False)
then in your view the query can become
def get_context_data(self, **kwargs):
context = super(LandingView, self).get_context_data(**kwargs)
qs = coremodels.Startup.objects.all().order_by('created_on')
context['first_ones'] = qs[:5]
context['last_ones'] = qs[-5:]
return context

Django: is_authenticated and is_anonymous both return true after logout

I am using django-registration, and just set it up.
{{user.is_authenticated }}
is true, even though i went already to /accounts/logout/ and logged the user out.
{{user.is_anonymous }}
returns true also. According to django docs, those two should be different:
is_anonymous: Always returns False. This is a way of differentiating User and AnonymousUser objects. Generally, you should prefer using is_authenticated() to this method.
and
is_authenticated: Always returns True. This is a way to tell if the user has been authenticated. This does not imply any permissions, and doesn't check if the user is active - it only indicates that the user has provided a valid username and password.
I am using the standard views that come with django-registration and haven't touched them yet. In the tempalate i have the following code:
{% if user.is_authenticated %}
{% user }}
{% if user.is_anonymous %}
is anonymous
{% endif $}
{% else %}
gotta login
{% endif %}
Where would the problem be? I will be really thankful!
UPDATE:
i have noticed that on the homepage, it both is_authenticated and id_anonymous return True, while if i go to /accounts/login before loging in, only is_anonymous returns true as it should be. And also, on the homepage, i have the following view if that helps:
def home(request):
return render_jinja(request, 'index.html', blah = 'ga')
UPDATE 2:
print(request.user.is_authenticated()) gives False. Then, i have:
return render_jinja(request, 'index.html', blah = 'ga')
and in the template, user.is_authenticated returns FALSE.
UPDATE 3:
If i use render_to_response, instead of render_jinja, all is good. still don't know how to fix this though :(
It seems like you are trying to figure out two things at once; what is the correct way to use jinja templates and what is the deal with User/AnonymousUser. Maybe try to figure out these problems one at a time.
I have no experience with jinja but you may want to check and make sure that you are taking differences between jinja and django template syntax into account. The biggest difference I know of is that a method call requires explicit parenthesis. So the is_authenticated and is_anonymous calls in your example need parenthesis.
Jinja style {{ user.is_authenticated() }}
Django style {{ user.is_authenticated }}
If that does not solve the problem, try installing django-debug-toolbar and take a look at the context for your template. Check and see if user is None or an object (User or AnonymousUser).
You can also read up on AnonymousUser and see an example of checking for an authenticated user in the docs. In a nutshell, for an AnonymousUser object is_anonymous() always returns True instead of False and is_authenticated() always returns False instead of True.
Smack on the head. I read somewhere:
if user.is_authenticated:
....# Always true, since it is a method!
And so, instead of having {{user.is_authenticated}} in template, it should be {{user.is_authenticated()}}

Unable to get custom context processor to be invoked

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.

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.

Categories