Login Required Django Classed Based View - django

Totally beginner question.
I have this view in my app Foo:
class PaymentsView(LoginRequiredMixin, CreateView):
login_url = '/login/'
redirect_field_name = 'redirect_to'
# -- Omitted ...
I have read the django documentation but I didn't see where to put my file "login.html" and how can I set the url for that. When I run the code show the 404 error.

Setting login_url will redirect to a URL within your project, which is then handled by URL Dispatcher. You'll need to include a path to that URL within your URLConf, just like you would with any other URL:
urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('login/', views.login),
]
You'll then need to write a view to handle the login. Django provides pre-written views and URL patterns that handle this with its login system.

Related

Replace Django Admin Login page

I need to replace the Django Admin Login page. The reason for that is that I've added some extra authentication at my own login page, however, I don't know how to override the login on the admin site.
Here is the solution. Inside urls.py, add the path to the new login page above your admin URLs like this
path('admin/login/', login_view, name='new_admin_login'), # login_view is the custom login view
path('admin/', admin.site.urls),
Creating a custom AdminSite is the Django way of doing such things. Specifically, in your case set the AdminSite.login_form
from django.contrib.admin import AdminSite
from django.contrib.auth.forms import AuthenticationForm
from django.urls import path
class CustomAuthenticationForm(AuthenticationForm):
# override the methods you want
...
class CustomAdminSite(AdminSite):
login_form = CustomAuthenticationForm
admin_site = CustomAdminSite()
urlpatterns = [
path("admin/", admin_site.urls),
]

Django/authentification: how to make login page = home page?

I develop Django web app using Django authentification backend.
It works without having to define any views or forms, only template to 'bootstrap' it.
But I would like to change 'navigation' url and probably 'redesign' template using django-crispy-form.
But the first step is make user directly access Login page when the 'root' url (https://<my_domain>/) is enter in the navigation adress bar.
Currently, user access home page of my web app that contain a login button that redirect to https://<my_domain>/registration/login
Do I need to override all authentification views (and forms for design) and change url as needed?
Or is there an easiest way, maybe using settings.py to make user redirect to login page from root url?
project
- app
- core
- settings
- base.py
- ...
- views.py
- urls.py
- app1
- forms.py
- views.py
- templates
- app1
- registration # <= currently no forms.py nor views.py
- templates
- registration
- login.html
- password_change_done.html
- ...
- static
- templates
- layout
- base.html
- home.html
core/urls.py
urlpatterns = [
path('', views.home, name='home'), # <= 'root' url
# path('registration/', include('registration.urls')), # <= registration views override
path('registration/', include('django.contrib.auth.urls')),
]
core/settings.py
LOGIN_URL = 'home'
LOGIN_REDIRECT_URL = 'home'
LOGOUT_REDIRECT_URL = 'login'
You cannot have that:
LOGIN_URL = 'home'
Use classic solution:
LOGIN_URL = 'login'
And then use decorator mentioned by #AnkitTiwari if you operate in Function Based Views just on top on home view:
#login_required
def home_view(request):
Or LoginRequiredMixin in Class Based Views:
from django.contrib.auth.mixins import LoginRequiredMixin
class HomeView(LoginRequiredMixin, View):

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')),
# ]

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.