I have wrestled with this one for a bit and googled and looked through documentation, so I guess its time to ask. I am trying make my app redirect to the last viewed page after logging in. I am running django 1.2.4 and have had no luck so far.
This Stack Overflow thread seemed like it would do the trick but I have not had success with it:
Django: Redirect to previous page after login...
Currently after logging in from any view I am redirected to: //localhost:1100/accounts/profile/
settings.py has this suggested code:
"django.core.context_processors.request",
With this as my login button link:
login
I also made sure to import the RequestContext in my views.py file:
from django.template import RequestContext
I get the impression this is not working. Also I noticed now
login URL has a partial next URL in it:
//localhost:1100/accounts/login/?next=
Suggestions?
Thanks in advance!
As sdolan said, you can use the login_required decorator, but also there are a few more possiblities:
Form action:
<form method="post" action="{% url django.contrib.auth.views.login %}?next={{request.path}}">
Next hidden field:
<input type="hidden" name="next" value="{{request.path}}" />
With a link to the login form:
Login
For using them, you have to pass the Request Context in the corresponding view. Examples of doing this can be found here: http://lincolnloop.com/blog/2008/may/10/getting-requestcontext-your-templates/
If you use the login_required decorator on your views, it will do this for you automatically.
This is confirmed by experience, and explained in the docs:
If the user isn't logged in, redirect
to settings.LOGIN_URL, passing the
current absolute path in the query
string. Example:
/accounts/login/?next=/polls/3/.
Related
I'm trying to build a simple website with login functionality very similar to the one here on SO.
The user should be able to browse the site as an anonymous user and there will be a login link on every page. When clicking on the login link the user will be taken to the login form. After a successful login the user should be taken back to the page from where he clicked the login link in the first place.
I'm guessing that I have to somehow pass the url of the current page to the view that handles the login form but I can't really get it to work.
EDIT:
I figured it out. I linked to the login form by passing the current page as a GET parameter and then used 'next' to redirect to that page. Thanks!
EDIT 2:
My explanation did not seem to be clear so as requested here is my code:
Lets say we are on a page foo.html and we are not logged in. Now we would like to have a link on foo.html that links to login.html. There we can login and are then redirected back to foo.html.
The link on foo.html looks like this:
<a href='/login/?next={{ request.path }}'>Login</a>
Now I wrote a custom login view that looks somewhat like this:
def login_view(request):
redirect_to = request.REQUEST.get('next', '')
if request.method=='POST':
#create login form...
if valid login credentials have been entered:
return HttpResponseRedirect(redirect_to)
#...
return render_to_response('login.html', locals())
And the important line in login.html:
<form method="post" action="./?next={{ redirect_to }}">
So yeah thats pretty much it, hope that makes it clear.
You do not need to make an extra view for this, the functionality is already built in.
First each page with a login link needs to know the current path, and the easiest way is to add the request context preprosessor to settings.py (the 4 first are default), then the request object will be available in each request:
settings.py:
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",
)
Then add in the template you want the Login link:
base.html:
Login
This will add a GET argument to the login page that points back to the current page.
The login template can then be as simple as this:
registration/login.html:
{% block content %}
<form method="post" action="">
{{form.as_p}}
<input type="submit" value="Login">
</form>
{% endblock %}
To support full urls with param/values you'd need:
?next={{ request.get_full_path|urlencode }}
instead of just:
?next={{ request.path }}
This may not be a "best practice", but I've successfully used this before:
return HttpResponseRedirect(request.META.get('HTTP_REFERER','/'))
Django's built-in authentication works the way you want.
Their login pages include a next query string which is the page to return to after login.
Look at http://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.decorators.login_required
I linked to the login form by passing the current page as a GET parameter and then used 'next' to redirect to that page. Thanks!
I encountered the same problem. This solution allows me to keep using the generic login view:
urlpatterns += patterns('django.views.generic.simple',
(r'^accounts/profile/$', 'redirect_to', {'url': 'generic_account_url'}),
)
In registration/login.html (nested within templates folder) if you insert the following line, the page will render like Django's original admin login page:
{% include "admin/login.html" %}
Note: The file should contain above lines only.
See django docs for views.login(), you supply a 'next' value (as a hidden field) on the input form to redirect to after a successful login.
You can also do this
<input type="hidden" name="text" value="{% url 'dashboard' %}" />
I followed this page to set up a django registration site. It's pretty awesome, and registration and authentication are nicely wrapped.
But, it doesn't show me, how do I check if a user is logged in, who this user is, before displaying a webpage? and how do I direct the user to a new page after logged in?
Thanks!
In a view, you can use if request.user.is_authenticated(): and the variable for the current user is request.user
In a template, you can use {% if user.is_authenticated %} and the variable for the current user is user
For redirecting a user after logging in, you can set up LOGIN_REDIRECT_URL variable in settings.py
In .py documents
You can either use this inside every view
if not request.user.is_authenticated:
#do something
or this just before every view
#login_required
Remember that this one requires importing from django.contrib.auth.decorators import login_required
and you may also want to write LOGIN_URL = "/loginurl/" in your settings.py to get non-logged users redirected to an specific URL instead of the default one accounts/login)
In .html documents
{% if not user.is_authenticated %}
Login is required
{% endif %}
Redirecting after logging in
You can either modify LOGIN_REDIRECT_URL in settings.py
or redirect("/indexpage") after the user has been logged in.
This last one requires importing from django.shortcuts import redirect
You can also use a login required decorator before your view :
#login_required()
It redirects a user to the login page if a non logged in user tries to access your view
You will find more on this page :
https://docs.djangoproject.com/en/dev/topics/auth/default/#topic-authorization
I have a view defined for a url 'site/main/'. I would like to be able to have (unauthenticated) users redirected to the default '/admin/' page for login, then redirected to the '/main/' page after successful login. I followed the django documentation, but I must be missing something as I am unable to get this to work.
My view looks like:
def main(request):
if not request.user.is_authenticated():
return HttpResponseRedirect('admin/?next=%s' % request.path)
else:
I get an error:
Page not found (404)
Request Method: GET
Request URL:http://sitename:8080/main/admin/?next=/main/
Any help is greatly appreciated !
You're missing an initial / in the URL: /admin/?next=...
However this still won't work, as the admin URL doesn't know anything about the next parameter. That's only for the actual login views. With your code, the user will be logged into the admin but will not be redirected back to your page.
You should build a login template and wire it up to the built-in login views. Then instead of checking is_authenticated in the view, you should just use the login_required decorator.
#login_required
def main(request):
...
Your request.path shouldn't be /main/. Try it without the first.
If you want to redirect to admin for login for specific view, and then to redirect back to the view url after successful login you only need to do two things:
Add LOGIN_URL to settings.py inside your django project module:
...
LOGIN_URL = '/admin/login/'
Add #login_required as decorator to your view function inside views.py:
from django.contrib.auth.decorators import login_required
...
#login_required
def main(request):
Once you set LOGIN_URL = '/admin/login/' you can use #login_required on whatever view in entire django project and it will redirect to admin for login and after successful login will redirect back to the view url.
Also now you don't need to use is_authenticated any more inside of a view as Daniel Roseman already said.
The good thing is that now you also don't need to build a login template and wire it up to the built-in login views.
What is also good with this approach is the you have flexibility to easily add or remove this kind of authentication to whatever view you want.
urls.py:
url('^', include('django.contrib.auth.urls')),
registration/login.html:
<h3>Login foo</h3>
<form method="post" action="">
{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Login">
</form>
views.py
def only_for_users(request):
if not request.user.is_authenticated():
return HttpResponseRedirect('/login/?next=%s' % request.path)
// fetch some really interesting data
env=(django.get_version(),settings.BASE_DIR,sys.version)
envMod=collections.OrderedDict(sorted(sys.modules.items()))
return render(request,'env.html',{'env':env, 'envMod':envMod})
It works for Django 1.6 and uses the built-in login (look at the urls.py) and template. So you do not need to build a view function.
Info on urls
I my recent Django-project I use mako templates.
About Cross Site Request Forgery CSRF.
In django templates there is the tag {% csrf_token %} to protect from hackers.
What about mako templates? Is there any analog of csrf_token or there is another protection mechanism???
Thanks!
I ran into the same problem just today (that's why I ended up here). I found a solution, at least, for what I wanted to do, which is pass some POST data to another view through an HTML form. Here it is:
From your first view, get a CSRF Token and add it to your (Mako) context:
from djangomako.shortcuts import render_to_response as render
from django.core.context_processors import csrf
def first_view(request):
"""This view generates a form whose action is 'second_view'."""
context = { "csrftoken": csrf(request)["csrf_token"] }
return render("path/to/yourtemplate.html", context)
yourtemplate.html's form must have a field named “csrfmiddlewaretoken” whose value is the CSRF Token, which we placed in the context as “csrftoken”. As in:
<input type="hidden" name="csrfmiddlewaretoken" value="${ csrftoken }" />
Source: Cross Site Request Forgery protection (Django 1.5 Docs)
There's some sample code at Django Snippets that looks to do this, although judging by the comments, you may need to fiddle a bit. If you have trouble, you basically want to make sure that you're duplicating the Django stock CSRF tag (click the link, start on line 87).
I'm having trouble with my URL forwarding after successful login.
The django default for 'LOGIN_REDIRECT_URL' is '/accounts/profile/'. In my case it should forward to '/user/{{ user.username }}/'
I went to overwrite it in my settings file but have encountered a syntax issue. Here's the code:
LOGIN_REDIRECT_URL = "/user/%s/" % user.username
When I use the following line in my login form, it works, but only if the page is reloaded first. Kinda strange.
<input type="hidden" name="user" value="/user/{{ user.username }}/" />
So what changes must I make to my settings.py to load the username on redirect?
Thanks.
You may want to create a custom login instead and use the views described in django user authentication.
Of course overriding the view where /accounts/profile/ points to and manually setting the redirect url there is an option, but its not a very elegant solution.
Of course there's a syntax issue, you're referencing a variable, user, in settings.py that doesn't exist there. It might help you to go through a Python tutorial to understand Python's scoping rules.
In any case, settings.py is for static global settings. Usernames obviously vary per user, so you can't put a dynamic setting there.