Replace Django Admin Login page - django

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

Related

Django: how to route URL requests to django.contrib.admin functions

I would like Django to return the same response for requests to /myapp/add as /admin/myapp/mymodel/add.
myproject/myapp/models.py defines the model and myapp/admin.py registers with django.contrib.admin.
myproject/myapp/models.py:
from django.db import models
class MyModel(models.Model):
...
myproject/myapp/admin.py:
from django.contrib import admin
from .models import MyModel
admin.site.register(MyModel)
I am stuck on how to route the request to django.contrib.admin in the project's urlpatterns:
myproject/myproject/urls.py:
urlpatterns = [
url(r'^$', views.home_page, name='home'),
url(r'^admin/', admin.site.urls),
url(r'^myapp/add', ??????),
]
From printing the return from resolve('/admin/myapp/mymodel/add/') this looks like part of the answer:
ResolverMatch(func=django.contrib.admin.options.add_view, args=(), kwargs={}, url_name=myapp_mymodel_add, app_names=['admin'], namespaces=['admin'])
Well let me say that seems like a weird thing to do, but anyway:
in the file: django.contrib.admin.options.py we see:
class ModelAdmin(BaseModelAdmin):
we see that the add view returns
_changeform_view()
which uses the template
django/contrib/admin/templates/change_form.html
So you would want to render that template in your view.
but it would be missing a bunch of context items,
so you would basically have to re-implement the django.admin.options._changeform_view
and then copy the template django/contrib/admin/templates/change_form.html to your apps' template directory
def admin_add(request):
# admin.changeform_view code here
return render(request, "myapp/change_form.html", {context{)
ps. I assume the admin site view assumes the user is the "superuser" and not a normal user so you would want to account for that as well..

How to redirect the user back to the login page after logout in django/allauth?

I installed a very basic project on django with the allauth module. It works well...except that i have a 404 page when i try to logout using http://localhost:8000/accounts/logout/.
The urls.py
urlpatterns = [
url(r'^accounts/', include('allauth.urls')),
url(r'^aboutus/$', TemplateView.as_view(template_name="aboutus.html"), name="aboutus"),
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^admin/', include(admin.site.urls)),
]
and in settings.py i set ACCOUNT_LOGOUT_ON_GET= True to avoid the logout confirmation.
My goal is to set path: login page-->aboutus:click on logout button--> login page.
I read on internet a lot of stuff but it still does not work.
Please help
solution in the setting file : ACCOUNT_LOGOUT_REDIRECT_URL ="/accounts/login"
If I understand you right, there is an answer for your question in official docs. Basically you just need to write your own adapter, it may look like:
# project/settings.py:
ACCOUNT_ADAPTER = 'project.users.adapter.MyAccountAdapter'
# project/users/adapter.py:
from django.conf import settings
from allauth.account.adapter import DefaultAccountAdapter
class MyAccountAdapter(DefaultAccountAdapter):
def get_login_redirect_url(self, request):
path = "/accounts/{username}/"
return path.format(username=request.user.username)

how to change a default django admin login view to generate token on login to admin site

my site.py:
from django.contrib.admin import AdminSite
class OptiAdminSite(AdminSite):
def get_urls(self):
from django.conf.urls import patterns, url, include
from core import views
from django.contrib.contenttypes import views as contenttype_views
urlpatterns = patterns('',
#url(r'^$', wrap(self.index), name='index'),
url(r'^login/$', views.login, name='login'),
url(r'^logout/$', views.logout, name='logout'),
)
return urlpatterns
opti_site = OptiAdminSite()
I'm developing an authentication API. When user logs in to my API it generates a code which get destroyed once user hit logout.
My problem is that whenever I'm running my API and django admin site in same browser, then if I login into admin-site It automatically login me in my API too with out any token. When I try to logout in that case from my API it generates an error - 'Token does not exist'. I want to generate token when admin user login to admin-site.
I've tried to do it with above trick as in official documentation but didn't find the right way to do it.
Please suggest me the correct way to do it. Is it necessary to make a separate app for it?
Thanks! in advance.
This solution is almost complete... Almost, because you're simply creating your own admin site in opti_site variable, but probably not using it anywhere.
To make it work, you can monkey-patch default admin site with your site, using:
from django.contrib import admin
admin.sites.site = opti_site
admin.site = admin.sites.site
Remember that you must do it before root urlpatterns definition (especially before defining urls to your admin site).
Another approach is to change default admin to your admin in include of url patterns:
url(r'^admin/', include(opti_site.urls)),

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.