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
Related
I have a simple form:
{% block content %}
<p> Upload invoices </p>
<form method="post" action="{% url 'upload_thing ' %}" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="invoice_thing">
<button type="submit">Upload</button>
</form>
I have a view
#require_POST
#transaction.atomic
def upload_thing(request):
....
How do I make sure that the no one can hit the post endpoint via curl or postman?
I want the end point to be accessible only by hitting the form button. The only people who can do this are admin users.
How do I accomplish this?
To be honest, you shouldn't prevent curl or wget requests from django application. It can be done from a reverse proxy server, for example in NGINX you can put the following configuration:
if ($http_user_agent ~* (wget|curl) ) {
return 403;
}
Still, its not a proper protection, User-Agent information can be spoofed. More information can be found in this serverfault answer.
If you want to prevent people accessing this page who aren't admin, then you can simply put a restriction on the view like this:
from django.core.exceptions import PermissionDenied
from django.contrib.auth.decorators import login_required
#login_required
#require_POST
#transaction.atomic
def upload_thing(request):
if not request.user.is_superuser:
raise PermissionDenied()
# rest of the code
The right way to do this in python is via decorators.
from django.contrib.auth.decorators import login_required, user_passes_test
#user_passes_test(lambda user: user.is_superuser)
def upload_thing(request):
In this way you restrict the method and not the html page.
So only logged admin can use upload_thing (from curl, postman, or html form).
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 am using Django=1.6.1.
Currently in my project, the admin system takes me to admin dashboard after a successful admin login (i.e: localhost:8000/admin/). From here I can visit most of my apps like users, categories, groups etc..
90% of the time I want to visit the users admin page (i.e localhost:8000/admin/my_project/users/). thus I am trying to find a way to redirect the admin login to admin users page rather than the dashboard. How can I do this?
I do not know if this is the right way to tackle this issue but this is how I have solved my problem.
I created a subclass of AdminSite called CustomAdminSite and overwritten the login() to accept a redirect url using the REDIRECT_FIELD_NAME(i.e using the 'next' hidden field option).
class CustomAdminSite(AdminSite):
#never_cache
def login(self, request, extra_context=None):
"""
Displays the login form for the given HttpRequest.
"""
from django.contrib.auth.views import login
context = {
'title': _('Log in'),
'app_path': request.get_full_path(),
REDIRECT_FIELD_NAME: settings.ADMIN_LOGIN_REDIRECT_URL,
}
context.update(extra_context or {})
defaults = {
'extra_context': context,
'current_app': self.name,
'authentication_form': self.login_form or AdminAuthenticationForm,
'template_name': self.login_template or 'admin/login.html',
}
return login(request, **defaults)
site = CustomAdminSite()
in urls.py
admin.site.login = path.to.custom.site.login
in settings.py
ADMIN_LOGIN_REDIRECT_URL = '/admin/my_project/users/'
P.S: please let me know if there is a better way to do this :)
Currently on Django (and since version 1.8) you can reverse your admin urls to redirect to any admin page.
For example:
The url you want to redirect to: /admin/my_project/users/
The reference: href="{% url 'admin:app_list' 'app_name' %}
The implementation: href="{% url 'admin:app_list' 'users' %}
Assuming you only have one model MyUser inside your users app, you can go directly into the admin list view of that model.
Reference: href="{% url 'admin:app_label_model_name_changelist' %}
Implementation: href="{% url 'admin:users_myuser_changelist' %}
You can do it by overriding the 'admin:index' url (the url named 'index' within admin namespace).
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 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/.