Two views same URL - django

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')

Related

Django - Logout Redirect to Login Page

i am trying to redirect to login page after logout but some issues are coming.
urls.py
This is my actual logout routes and it works for me but it does not redirect me to login page
path('logout/', auth_views.LogoutView.as_view(template_name='users/logout.html'), name='logout'),
Changing logout.html -> login.html
It destroys the session and logout the user but the problem is that when i click logout it redirects to login page but login input fields are not showing
path('logout/', auth_views.LogoutView.as_view(template_name='users/login.html'), name='logout'),
And if i am using below path(route). It is not destroying session nor logout
path('login/', auth_views.LogoutView.as_view(template_name='users/login.html'), name='logout'),
Add in you settings file
LOGOUT_REDIRECT_URL = 'login/'
Refer https://docs.djangoproject.com/en/2.1/ref/settings/#logout-redirect-url
Also Changing logout.html -> login.html, is not required please revert it back
In my case I had to list my account/user application above admin.
before
'django.contrib.admin',
'account.apps.AccountConfig'
after
'account.apps.AccountConfig',
'django.contrib.admin',
There are multiple ways to do this.
Before doing anything, make sure to import
from django.contrib.auth import views as auth_views
from django.urls import path, reverse_lazy
Then, you can do this
path('/logout', auth_views.logout_then_login, name='logout')
You can define the login URL in settings.py like #nagesh mentioned.
There's another way to handle this and specially, comes handy when you have logout buttons at multiple places and you want the user to land to different pages after clicking different logout buttons in your interface.
path('logout/', auth_views.LogoutView.as_view(
next_page=reverse_lazy('Userauth:login') # you can use your named URL here just like you use the **url** tag in your django template
), name='logout'),
I suggest that you use reverse_lazy to define the redirect URL, it can create dynamic URL very easily and you don't have to worry if you ever change your URL structure.

How to redirect to another page

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:
...

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.