How to extend django.contrib.auth views? - django

How I've Arranged Templates : I have placed my login.html in /templates/registration folder of Django. So, the Django takes necessary care of accounts/login ,accounts/logout url requests and renders as per request. And I haven't to code for the individual login and logout functions.
What I am trying to Achieve : I want to authenticate users at login request, when they requests the login page:
If user is anonymous user, I want to render the normal login page.
However, If the user is authenticated thats already logged in. I want to display an error and not the logged page.
I want to achieve this in the views.py and urls.py and not in the templates by:
{% if user.is_authenticated %}
{% if user.is_anonymous %}
Urls.py
from django.conf.urls import url
from django.contrib.auth import views as auth_views
from . import views
urlpatterns=[
url(r'^register/$', views.register, name='register'),
url(r'^logout/$', auth_views.logout, {'next_page' : 'Homepage'}, name='logout'),
]

You can wrap the view with your own, which either redirects or calls the original.
def wrapped_login(request):
if request.user.is_authenticated:
return redirect('whatever')
else:
return auth_views.login(request)

Provide LOGIN_REDIRECT_URL = '/' in settings.py. Then use the following url for login page:
urlpatterns = [
url(r'^login/',
auth_views.LoginView.as_view(redirect_authenticated_user=True),
name='login'),
]
This will redirect your user to the URL provided in settings file if they try to login even after being authenticated.

Related

How to redirect from a view in one app to a view in another?

I am trying to build a job-board type of website. Right now I have user authentication (login, logout, register, password change, etc) in one app (account) and the job model and all other views/templates in another app(job).
To have the user log in, I used the views found in django.contrib.auth(this is account/urls.py):
from django.urls import path
from django.contrib.auth import views as auth_views
urlpatterns = [
path('login/', auth_views.LoginView.as_view(), name = 'login'),
]
In the job app I have created a urls.py file:
from django.urls import path
from . import views
urlpatterns = [
path('dashboard/', views.dashboard, name = 'dashboard'),
]
Upon logging in, I would like the user to be redirected to this dashboard URL/view found in the job app. How can I do this? I know that if I just put the dashboard view/url into the account app all I would need to do is add this to settings.py:
LOGIN_REDIRECT_URL = 'dashboard'
But, how can I redirect to a view in another app?
Final note: I separated this into two apps in the first place because I've read that is good practice, but am not sure if it's needed here.
Test this:
LOGIN_REDIRECT_URL = reverse_lazy('dashboard')
in settings.py:
LOGIN_REDIRECT_URL = reverse_lazy('job:dashboard')
This only works for redirection once logged in.
[settings.py]:
LOGIN_REDIRECT_URL = 'dashboard'
If you want to redirect urls from any app to another, you must use static tags.
[file.html]
{% load static %}
and then:
<a href="{% url 'dashboard' %}">

How to set custom admin login URL in Django Admin on session timeout?

I wrote a Django app which has an external authentication system reacheable at some URL (say, https://.../myproject/login). This is working well.
However, when the session expires, the user gets redirected to the default login url which is https://.../myproject/admin). I'd like to change the behavior of the app so if the session expires, the user should be redirected to https://.../myproject/login and only use the /admin login when explicitly opened.
Is there a built-in way to do this in Django?
Django admin redirects the users to /admin/login when the session is expired or session is missing.
There are several ways to redirect users to https://.../myproject/login instead of https://.../myproject/admin/login.
Approach 1:
Override the view of myproject/admin/login URL with the view of myproject/login.
Let's say that myproject/login uses LoginView to render external system's login page, then add url(r'^admin/login/?$', LoginView.as_view(), name='admin:login') just above url(r'^admin/', include(admin.site.urls)) in myproject/myproject/urls.py
urlpatterns = [
url(r'^admin/login/?$', LoginView.as_view(), name='admin:login'),
url(r'^admin/', include(admin.site.urls)),
]
Pros:
Render the external system's login page instead of default Django admin login page on /myproject/admin/login
Cons:
The URL still points to myproject/admin/login
No way to access the default admin login page
Approach 2:
Override the view of myproject/admin/login url and redirect the user to myproject/login
Lets create a new view AdminLoginView then add url(r'^admin/login/?$', AdminLoginView.as_view(), name='admin:login') just above url(r'^admin/', include(admin.site.urls)) in myproject/myproject/urls.py
from django.core.urlresolvers import reverse
class AdminLoginView(TemplateView):
def get(self, request, *args, **kwargs):
"""
Assuming the name of the external system's login url is "login"
"""
return HttpResponseRedirect(reverse('login'))
urlpatterns = [
url(r'^admin/login/?$', AdminLoginView.as_view(), name='admin:login'),
url(r'^admin/default-login/?$', admin.site.login, name='default-admin-login'),
url(r'^admin/', include(admin.site.urls)),
]
Pros:
The URL changes to myproject/login
Cons:
You have to add extra code for the default login page.
I would recommend approach 2 to solve the problem mentioned in the question.
Thanks.
You can use LOGIN_URL and LOGOUT_REDIRECT_URL
https://docs.djangoproject.com/en/2.2/ref/settings/#login-url
Redirect to myproject/login for login (Default redirects to /accounts/login/)
LOGIN_URL = '/myproject/login/'
Redirect to the login page after log out (Default to None).
LOGOUT_REDIRECT_URL = '/myproject/login/'
IMO the best possible solution is to override the function for login view.
To do this add these lines of code in your urls.py containing the 'admin/'
# urls.py
def login(request):
if request.user and request.user.is_authenticated and request.user.is_active and request.user.is_staff:
return HttpResponseRedirect(reverse('admin:index', current_app='admin'))
else:
return HttpResponseRedirect(reverse('index', current_app='your_app_name'))
admin.site.login = login
# The lines below probably exist
# urlpatterns = [
# path('admin/', admin.site.urls),
# path('', include('your_app.urls')),
# ]

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.

I can't get my Django URLs to work

My code is as follows:
root urls.py
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'', include('app.urls')),
]
My applications url is like so
urlpatterns = [
url(r'^$',views.login, name='login'),
url(r'^homepage/$', views.homepage, name='homepage'),
]
The first screen the user will see is the login screen (views.login). At the moment I just want to set the login button to be a url that takes them to the homepage (just for practice) but it doesnt seem to work.
The login html is like so
<button type="button">Log-In</button>
This should go to my urls page above...find the name 'homepage' and take me to views.homepage which is as so:
def homepage(request):
return render(request, 'application/homepage.html', {})
but my homepage doesnt get rendered and I have absolutely no idea why its driving me crazy.
Any help would be appreciated.
This is nothing to do with Django, but a pure HTML problem. You can't put a link inside a button. A button needs to be part of a form, and submits to the action value of that form. Either do that, and take the a tag out; or, remove the button, and just use the a.

Does using Django "is_superuser" require additional URL?

I'm creating an administrative interface/dashboard for a Django 1.7 project. Instead of creating a new admin application from scratch, I'm trying to use Django's built-in admin site. I have "root" (superuser) and "reviewer" (non-superuser) staff accounts. Both accounts are in the default "admin" group. Both accounts can log in to the admin site but some pages are accessible by both the root and reviewer accounts while access to others is limited to the superuser. I've created the two following views:
# mysite/apps/admin/views.py
from django.shortcuts import render
from django.contrib.auth.decorators import user_passes_test
#user_passes_test(lambda u: u.is_staff)
def all_admins(request, template):
return render(request, template)
#user_passes_test(lambda u: u.is_superuser)
def superuser_only(request, template):
return render(request, template)
The problem I'm running into is that if I log is using the reviewer account and click the anchor for the "superuser_only" page, I get the following error:
Page not found (404)
Request Method: GET
Request URL: http://localhost:8001/accounts/login/?next=/admin/super/
Using the URLconf defined in conf.urls, Django tried these URL patterns, in this order:
^admin/
^admin/all_admins/$ [name='all-admins']
^admin/super/$ [name='superuser-only']
The current URL, accounts/login/, didn't match any of these.
Is there something else I need to do to implement this superuser-only view and template so that this error doesn't occur if the reviewer clicks the link?
I followed the Django docs instructions and created my own copies of Django's base.html, base_site.html, and index.html templates in my mysite/apps/admin/templates/admin directory and then added the "all_admins" and "superuser_only" anchors to the bottom of the index.html page.
Here are my files:
# part of mysite/mysite/settings.py
TEMPLATE_DIRS = (
os.path.join(BASE_DIR, 'apps/admin/templates'),
os.path.join(BASE_DIR, 'apps/admin/templates/admin'),)
# mysite/mysite/urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^admin/all_admins/$',
'apps.admin.views.all_admins',
{'template': 'all_admins.html'},
name='all-admins'),
url(r'^admin/super/$',
'apps.admin.views.superuser_only',
{'template': 'superuser_only.html'},
name='superuser-only'),
)
Then user doesn't pass the test django redirects it to the login page. Defult url for this page is /accounts/login/. Set the LOGIN_URL setting to the admin's login page:
LOGIN_URL = 'admin:login'
Or, if you have non-staff users on the site, set the auth urls in the urls.py:
url('^accounts/', include('django.contrib.auth.urls')),
But this will require you to create several templates (login, logout, change password etc.)
UPDATE: If you want to show a message in the login page then you can create the custom login template for admin. Add this line to your urls.py:
admin.site.login_template = 'my_login.html'
And then create my_login.html template which is extended from admin/login.html:
{% extends 'admin/login.html' %}
{% block content %}
{% if user.is_staff %}
<p class="errornote">You need to be a superuser to access that page.</p>
{% endif %}
{{ block.super }}
{% endblock %}
UPDATE 2: If you don't want to change site-wide LOGIN_URL or implement auth by including django.contrib.auth.urls in your urls.py then you can pass login_url parameter to the #user_passes_test decorator:
#user_passes_test(lambda u: u.is_superuser, login_url='/admin/login/')
def superuser_only(request, template):
return render(request, template)