How to redirect to another page - django

Well, I have my own session and authentication routines in my app. When a user goes to app/login/ page, if he or she is not loggen in, then he/she sees a form to submit, otherwise I want to redirect the user to the root page app/. login view looks like this:
def index(request):
if sessionCheck(request):
# here I want to redirect one level above to app/
pass
else:
template = loader.get_template('login/login.html')
... other code which is not important
In PHP, I think, I would do it like this:
header("Location: /");
exit;
But how should I do exactly the same thing in Django?

You can use the redirect shortcut function:
from django.shortcuts import redirect
return redirect('some-view-name')
You can also specify a URL apart from a named view. So if your index url does not have a name, you can specify '/'.
This shortcut function is essentially the same as:
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
return HttpResponseRedirect(reverse('some-view-name'))
In order to have a named view, in your urls.py you have to provide a name argument. For instance:
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^some-view$', views.something, name='some-view-name'),
]
More on that on Django tutorial, Django URL dispatcher.

You can use redirect
if sessionCheck(request):
redirect(your_url)
else:
...

Related

Two views same URL

I have a single dashboard_view URL path("", view=dashboard_view, name="dashboard").
On this page you can see the homepage unauthenticated. However, if you login, I present a modal popup to allow a user to populate a CreateForm.
The issue is that the dashboard_view doesn't have the form ( I have that in another view ). What is the best practice for this? Best for the user to have different options on the same page without having to switch pages.
You can use the login_required decorator. In login_required login_url is an optional parameter if you have declared the login path in the settings.py file. If your entire site has a login URL is the same. You can put LOGIN_URL = 'login_form_url' in the settings.py file.
from django.contrib.auth.decorators import login_required
#login_required(login_url='/login_form_url/')
def dashboard_view(request):
return render(request,'app_name/dashboard.html')

How to bypass django admin index and go to a specific application page?

I've got a Django project with only one app.
I don't need the site admin (same as my app admin), so I would like to bypass the site admin and go directly to my app admin, i.e. go directly to mysite/admin/myapp/ after loging in and removing Home in the breadcrumb.
How can I do that?
Django Url Dispatcher scans all defined url definitions and redirect the request to the first matching url definition. At this point, url ordering is important, in urls.py file of your project root:
urlpatterns += patterns('',
...
(r'^admin/', include(admin.site.urls)),
...
)
You can define an url redirection form the admin index page url to a custom view
urlpatterns += patterns('',
...
(r'^admin/$', 'myapp.views.home'),
(r'^admin/', include(admin.site.urls)),
...
)
So, if the request url is your admin index page, then your custom view will be called, if it is an admin page (that starts with admin/) but not admin index page, then admin.site.urls will be executed...
in your myapp.views write a simple redirection view:
from django.http import HttpResponseRedirect
def home(request):
return HttpResponseRedirect("/myapp/")
What you can do is override the admin index page to redirect to app specific admin page.
As stated by #FallenAngel, you need to update the urls.py to have your view for admin index page. That view can redirect to inner app admin page.
from django.http import HttpResponseRedirect
from django.core import urlresolvers
def home(request):
return HttpResponseRedirect(urlresolvers.reverse('admin:app_list', args=("myapp",)))
You can comment it out in the INSTALLED_APPS if you don't want that in your project. Just to remove it from admin you need to unregister. Check it out here.
Another hack is, you can override the admin url mysite/admin/ to simply redirect to mysite/admin/myapp/ in which you don't need to define your own redirect view. Django DRY rocks there. :)
from django.http import HttpResponseRedirect
urlpatterns = patterns('',
url(r'^mysite/admin/$', lambda x: HttpResponseRedirect('/mysite/admin/myapp/')),
url(r'^mysite/admin/', include(admin.site.urls)),
)
For more customization you need to change the admin index page by customizing the admin templates. Doc is here.
https://docs.djangoproject.com/en/1.3/intro/tutorial02/#customize-the-admin-index-page
The cleanest and easiest way is to use the generic RedirectView in urls.py:
from django.core.urlresolvers import reverse_lazy
from django.views.generic import RedirectView
urlpatterns = patterns('',
url(r'^admin/$', RedirectView.as_view(url=reverse_lazy('admin:app_list',
args=('myapp',)))),
url(r'^admin/', include(admin.site.urls)),
)

How can I not use Django's admin login view?

I created my own view for login. However if a user goes directly to /admin it brings them to the admin login page and doesn't use my custom view. How can I make it redirect to the login view used for everything not /admin?
From http://djangosnippets.org/snippets/2127/—wrap the admin login page with login_required. For example, in urls.py:
from django.contrib.auth.decorators import login_required
from django.contrib import admin
admin.autodiscover()
admin.site.login = login_required(admin.site.login)
You probably already have the middle two lines and maybe even the first line; adding that fourth line will cause anything that would have hit the admin.site.login function to redirect to your LOGIN_URL with the appropriate next parameter.
While #Isaac's solution should reject majority of malicious bots, it doesn't provide protection for professional penetrating. As a logged in user gets the following message when trying to login to admin:
We should instead use the admin decorator to reject all non-privileged users:
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib import admin
[ ... ]
admin.site.login = staff_member_required(admin.site.login, login_url=settings.LOGIN_URL)
To the best of my knowledge, the decorator was added in 1.9.
I found that the answer above does not respect the "next" query parameter correctly.
An easy way to solve this problem is to use a simple redirect. In your site's urls file, immediately before including the admin urls, put a line like this:
url(r'^admin/login$', RedirectView.as_view(pattern_name='my_login_page', permanent=True, query_string=True))
Holá
I found a very simple solution.
Just tell django that the url for admin login is handle by your own login view
You just need to modify the urls.py fle of the project (note, not the application one)
In your PROJECT folder locate the file urls.py.
Add this line to the imports section
from your_app_name import views
Locate this line
url(r'^admin/', include(admin.site.urls))
Add above that line the following
url(r'^admin/login/', views.your_login_view),
This is an example
from django.conf.urls import include, url
from django.contrib import admin
from your_app import views
urlpatterns = [
url(r'^your_app_start/', include('your_app.urls',namespace="your_app_name")),
url(r'^admin/login/', views.your_app_login),
url(r'^admin/', include(admin.site.urls)),
]
http://blog.montylounge.com/2009/07/5/customizing-django-admin-branding/
(web archive)
I'm trying to solve exactly this problem and I found the solution at this guys blog. Basically, override the admin template and use your own template. In short, just make a file called login.html in /path-to-project/templates/admin/ and it will replace the admin login page. You can copy the original (django/contrib/admin/templates/login.html) and modify a line or two. If you want to scrap the default login page entirely you can do something like this:
{% extends "my-login-page.html" %}
There it is. One line in one file. Django is amazing.
I had the same issue, tried to use the accepted answer, but has the same issue as pointed in the comment above.
Then I've did something bit different, pasting here if this would be helpful to someone.
def staff_or_404(u):
if u.is_active:
if u.is_staff:
return True
raise Http404()
return False
admin.site.login = user_passes_test(
staff_or_404,
)(admin.site.login)
The idea is that if the user is login, and tried to access the admin, then he gets 404. Otherwise, it will force you to the normal login page (unless you are already logged in)
In your ROOT_URLCONF file (by default, it's urls.py in the project's root folder), is there a line like this:
urlpatterns = patterns('',
...
(r'^admin/', include(admin.site.urls)),
...
)
If so, you'd want to replace include(admin.site.urls) with the custom view you created:
(r'^admin/', 'myapp.views.myloginview'),
or if your app has its own urls.py, you could include it like this:
(r'^admin/', include(myapp.urls)),
This is my solution with custom AdminSite class:
class AdminSite(admin.AdminSite):
def _is_login_redirect(self, response):
if isinstance(response, HttpResponseRedirect):
login_url = reverse('admin:login', current_app=self.name)
response_url = urllib.parse.urlparse(response.url).path
return login_url == response_url
else:
return False
def admin_view(self, view, cacheable=False):
inner = super().admin_view(view, cacheable)
def wrapper(request, *args, **kwargs):
response = inner(request, *args, **kwargs)
if self._is_login_redirect(response):
if request.user.is_authenticated():
return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL)
else:
return redirect_to_login(request.get_full_path(), reverse('accounts_login'))
else:
return response
return wrapper
You can redirect admin login url to the auth login view :
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('', include('your_app.urls')),
path('accounts/', include('django.contrib.auth.urls')),
path('admin/login/', RedirectView.as_view(url='/accounts/login/?next=/admin/', permanent=True)),
path('admin/', admin.site.urls),
]
As of August 2020, django.contrib.admin.sites.AdminSite has a login_template attribute. So you can just subclass AdminSite and specify a custom template i.e.,
class MyAdminSite(AdminSite):
login_template = 'my_login_template.html'
my_admin_site = MyAdminSite()
Then just use my_admin_site everywhere instead of admin.site.

How to specify the login_required redirect url in django?

I have a view function:
#login_required
def myview():
# do something
# respond something
pass
How can I specify the exact URL for this view function to be redirected?
LOGIN_URL in your settings
Reference:
LOGIN_URL
LOGIN_REDIRECT_URL
you can do this in your view works fine for me without declaring in settings.py
from django.contrib.auth.decorators import login_required
#login_required(login_url='/example url you want redirect/') #redirect when user is not logged in
def myview(request):
do something
return something #returns when user is logged in
default login url is: '/accounts/login/'
if you want to change it then go to settings.py
LOGIN_URL='/path/to/url'
LOGIN_REDIRECT_URL='/path/to/redirecturl'
this from documentation should be helpful:
https://docs.djangoproject.com/en/1.5/topics/auth/default/#the-login-required-decorator
#login_required(login_url='/accounts/login/')
def my_view(request):
...
Go to your setting.py
You can add this anywhere in your settings.py file but i prefer to place it at the bottom.
LOGIN_URL = '/login/'
NOTE: '/login/' is the URL segment that brings the user to the login page. The complete URL is similar to this "myexample.com/login/".
you can also take url from view
for example
path('login/', login_view, name='login_name'),
then decoratorwill be
#login_required(login_url='login_name')
In django project settings
add below code
LOGIN_REDIRECT_URL = 'path/to/url'
and then import this LOGIN_REDIRECT_URL in your views and add
`#login_required(login_url=LOGIN_REDIRECT_URL)`
to the top of your views you want to restrict it will work
We have two approaches, first is the best practice for code maintenance in the future, and the second will be a hassle when the URL for login changes
First approach
in setting.py import reverse_lazy, and set LOGIN_URL to the login namespace
from django.urls import reverse_lazy
LOGIN_URL = reverse_lazy('login')
In your views, you import login_required and require login before each function
from django.contrib.auth.decorators import login_required
#login_required()
def view_name(request):
pass
Second approach
This approach is not reliable since you won't have a defined variable holding your login URL namespace
In your views, you import login_required and require login before each function
from django.contrib.auth.decorators import login_required
#login_required(login_url='/path/to/login/')
def view_name(request):
pass
In both cases what is static is you will have to import login_required in views
Django 4+ makes this very easy.
In urls.py make sure you have a path with a name you can reference:
path('login/', login_view, name='login_name'),
Then in settings.py, all you need to do is add this to the bottom:
LOGIN_URL = 'login_name'
Now all your #login_required decorators will automatically send anyone not logged in to your login page. If you change that url in the future, the settings.py file stays updated since it's referencing the name and not the absolute url path.
I recommend against doing any of the 'path/to/url' approaches above since as soon as you change that path you then need to change everything. Reference the 'login_name' once in your settings.py file, and be done forever.
My signin/signup page was ignoring the ?next=... part of my path, and just redirecting to the home page, '/'.
By including:
<input type="hidden" name="next" value="{{ request.GET.next }}">
After my submit button, the redirect worked properly.

Django: Redirect logged in users from login page

I want to set up my site so that if a user hits the /login page and they are already logged in, it will redirect them to the homepage. If they are not logged in then it will display normally. How can I do this since the login code is built into Django?
I'm assuming you're currently using the built-in login view, with
(r'^accounts/login/$', 'django.contrib.auth.views.login'),
or something similar in your urls.
You can write your own login view that wraps the default one. It will check if the user is already logged in (through is_authenticated attribute official documentation) and redirect if he is, and use the default view otherwise.
something like:
from django.contrib.auth.views import login
def custom_login(request):
if request.user.is_authenticated:
return HttpResponseRedirect(...)
else:
return login(request)
and of course change your urls accordingly:
(r'^accounts/login/$', custom_login),
The Django 1.10 way
For Django 1.10, released in August 2016, a new parameter named redirect_authenticated_user was added to the login() function based view present in django.contrib.auth [1].
Example
Suppose we have a Django application with a file named views.py and another file named urls.py. The urls.py file will contain some Python code like this:
#
# Django 1.10 way
#
from django.contrib.auth import views as auth_views
from . import views as app_views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', auth_views.login, name='login',
kwargs={'redirect_authenticated_user': True}),
url(r'^dashboard/', app_views.Dashboard.as_view(), name='dashboard'),
url(r'^$', TemplateView.as_view(template_name='index.html'), name='index'),
]
From that file, the relevant part within the urlpatterns variable definition is the following, which uses the already mentioned redirect_authenticated_user parameter with a True value:
url(r'^login/', auth_views.login, name='login',
kwargs={'redirect_authenticated_user': True}),
Take note that the default value of the redirect_authenticated_user parameter is False.
The Django 1.11 way
For Django 1.11, released in April 2017, the LoginView class based view superseded the login() function based view [2], which gives you two options to choose from:
Use the same Django 1.10 way just described before, which is a positive thing because your current code will continue working fine. If you tell Python interpreter to display warnings, by for example running in a console terminal the command python -Wd manage.py runserver in your Django project directory and then going with a web browser to your login page, you would see in that same console terminal a warning message like this:
/usr/local/lib/python3.6/site-packages/django/contrib/auth/views.py:54:
RemovedInDjango21Warning: The login() view is superseded by the
class-based LoginView().
Use the new Django 1.11 way, which will make your code more modern and compatible with future Django releases. With this option, the example given before will now look like the following one:
Example
We again suppose that we have a Django application with a file named views.py and another file named urls.py. The urls.py file will contain some Python code like this:
#
# Django 1.11 way
#
from django.contrib.auth import views as auth_views
from . import views as app_views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/',
auth_views.LoginView.as_view(redirect_authenticated_user=True),
name='login'),
url(r'^dashboard/', app_views.Dashboard.as_view(), name='dashboard'),
url(r'^$', TemplateView.as_view(template_name='index.html'), name='index'),
]
From that file, the relevant part within the urlpatterns variable definition is the following, which again uses the already mentioned redirect_authenticated_user parameter with a True value, but passing it as an argument to the as_view method of the LoginView class:
url(r'^login/',
auth_views.LoginView.as_view(redirect_authenticated_user=False),
name='login'),
Take note that here the default value of the redirect_authenticated_user parameter is also False.
References
[1] Relevant section in Django 1.10 release notes at https://docs.djangoproject.com/en/dev/releases/1.10/#django-contrib-auth
[2] Relevant section in Django 1.11 release notes at https://docs.djangoproject.com/en/1.11/releases/1.11/#django-contrib-auth
anonymous_required decorator
For class based views
Code:
from django.shortcuts import redirect
def anonymous_required(func):
def as_view(request, *args, **kwargs):
redirect_to = kwargs.get('next', settings.LOGIN_REDIRECT_URL )
if request.user.is_authenticated():
return redirect(redirect_to)
response = func(request, *args, **kwargs)
return response
return as_view
Usage:
url(r'^/?$',
anonymous_required(auth_views.login),
),
url(r'^register/?$',
anonymous_required(RegistrationView.as_view()),
name='auth.views.register'
),
# Could be used to decorate the dispatch function of the view instead of the url
For view functions
From http://blog.motane.lu/2010/01/06/django-anonymous_required-decorator/
Code:
from django.http import HttpResponseRedirect
def anonymous_required( view_function, redirect_to = None ):
return AnonymousRequired( view_function, redirect_to )
class AnonymousRequired( object ):
def __init__( self, view_function, redirect_to ):
if redirect_to is None:
from django.conf import settings
redirect_to = settings.LOGIN_REDIRECT_URL
self.view_function = view_function
self.redirect_to = redirect_to
def __call__( self, request, *args, **kwargs ):
if request.user is not None and request.user.is_authenticated():
return HttpResponseRedirect( self.redirect_to )
return self.view_function( request, *args, **kwargs )
Usage:
#anonymous_required
def my_view( request ):
return render_to_response( 'my-view.html' )
For Django 2.x, in your urls.py:
from django.contrib.auth import views as auth_views
from django.urls import path
urlpatterns = [
path('login/', auth_views.LoginView.as_view(redirect_authenticated_user=True), name='login'),
]
Add this decorator above your login view to redirect to /home if a user is already logged in
#user_passes_test(lambda user: not user.username, login_url='/home', redirect_field_name=None)
and don't forget to import the decorator
from django.contrib.auth.decorators import user_passes_test
Since class based views (CBVs) is on the rise. This approach will help you redirect to another url when accessing view for non authenticated users only.
In my example the sign-up page overriding the dispatch() method.
class Signup(CreateView):
template_name = 'sign-up.html'
def dispatch(self, *args, **kwargs):
if self.request.user.is_authenticated:
return redirect('path/to/desired/url')
return super().dispatch(*args, **kwargs)
Cheers!
https://docs.djangoproject.com/en/3.1/topics/auth/default/#all-authentication-views
Add the redirect route in settings
LOGIN_URL = 'login'
And in the URLs add redirect_authenticated_user=True to LoginView
path('login/', auth_views.LoginView.as_view(template_name='users/login.html',redirect_authenticated_user=True), name='login')
I know this is a pretty old question, but I'll add my technique in case anyone else needs it:
myproject/myapp/views/misc.py
from django.contrib.auth.views import login as contrib_login, logout as contrib_logout
from django.shortcuts import redirect
from django.conf import settings
def login(request, **kwargs):
if request.user.is_authenticated():
return redirect(settings.LOGIN_REDIRECT_URL)
else:
return contrib_login(request, **kwargs)
logout = contrib_logout
myproject/myapp/urls.py
from django.conf.urls import patterns, url
urlpatterns = patterns('myapp.views.misc',
url(r'^login/$', 'login', {'template_name': 'myapp/login.html'}, name='login'),
url(r'^logout/$', 'logout', {'template_name': 'myapp/logout.html'}, name='logout'),
)
...
Assuming that you are done setting up built-in Django user authentication (and using decorators), add this in your settings.py:
LOGIN_REDIRECT_URL = '/welcome/'
NOTE: '/welcome/' here is the URL of the homepage. It is up to you what to replace it with.
All you have to do is set the "root" url to the homepage view. Since the homepage view is already restricted for logged on users, it'll automatically redirect anonymous users to the login page.
Kepp the url as it is.
And add something like:
(r'^$', 'my_project.my_app.views.homepage'),