Django - custom admin page not related to a model - python

I am using Django 1.7 with Mezzanine. I would like to have some page in admin, where the staff can call some actions (management commands etc.) with buttons and other control elements.
I would also like to avoid creating new model, or manually create a template and add link to it (if possible).
What is the most common/clean ways how to achieve that?

Actually it is simpler. Just before urlpatterns in urls.py patch admin urls like that:
def get_admin_urls(urls):
def get_urls():
my_urls = patterns('',
url(r'^$', YourCustomView,name='home'),
)
return my_urls + urls
return get_urls
admin.autodiscover()
admin_urls = get_admin_urls(admin.site.get_urls())
admin.site.get_urls = admin_urls

ModelAdmin.get_urls let you add a url to the admin url's. So you can add your own view like this:
class MyModelAdmin(admin.ModelAdmin):
def get_urls(self):
urls = super(MyModelAdmin, self).get_urls()
my_urls = patterns('',
(r'^my_view/$', self.my_view)
)
return my_urls + urls
def my_view(self, request):
# custom view which should return an HttpResponse
pass
https://docs.djangoproject.com/en/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_urls
I didn't try this out, but it seems to me that you can subclass a build-in admin view and let your custom template extend the build-in admin templates.

Related

How to add custom view to custom AdminSite in Django

im a beginner with Django and basically want to add a section in Django Admin where if I click on it, I have a view that can process data.
For example: I have models Campaign and Components which I can access through Django Admin and now I also want an Option "Analytics" that work the same way as if it was a model. Maybe this image will make clear what I want:
When I click on "Analytics" I want to call a view that can fill a html template with data that I calculate from my models e.g. build a table that counts my instances of Campaigns and Components.
What I've done so far:
create a custom AdminSite to overwrite the default AdminSite. Problem: I do not see my option appearing.
#admin.py
class MyAdminSite(admin.AdminSite):
def get_urls(self):
urls = super(MyAdminSite, self).get_urls()
custom_urls = [
path(r'myapi/test/', self.admin_view(testview)),
]
return urls + custom_urls
site_header = "My custom site"
admin_site = MyAdminSite(name="myadmin")
#apps.py
class MyAdminConfig(AdminConfig):
default_site = "myapi.admin.MyAdminSite"
#settings.py
INSTALLED_APPS = [
'rest_framework',
#'django.contrib.admin',
"myapi.apps.MyAdminConfig",
#views.py
#api_view(["GET", "POST"])
def testview(request):
print("testmyview")
return render(1, "mytest.html")
#urls.py
urlpatterns = [
path('admin/', admin_site.urls),
path('api/', include('myapi.urls')),
]
I tried to follow this tutorial:
https://adriennedomingus.medium.com/adding-custom-views-or-templates-to-django-admin-740640cc6d42
but I think after overwriting the get_urls() I should see a new option appearing on my Django Admin, which is not the case.

django admin remove login page

Is there anyway to delete django admin login page (mySite.com/admin) and use the user session which has logged in in main site (mySite.com)?
If any code is needed please tell me to add.
My middleware in settings.py is:
MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
.
.
.
.
.
]
update:
the reason is I want the admin first logs in with his account in website then open admin page. Other users would see admin link, but after clicking that they would see a message you don't have permission to see or change anything and they see nothing else. I just want myWebsite.com/admin be redirected to admin:index if the user is logged in and to myWebsite.com if he is not.
You can easily do this using your main urls.py file. Just redirect the admin login URL to your custom log-in page on your website. In the below sample you will notice the normal admin.site.urls being used AFTER admin/login and admin/logout (I assume you'll also have a custom log-out page). With these custom views being first they will take precedence and be used instead of the ones in admin.site.urls.
urlpatterns = [
url(r'^admin/login', your_custom_login_view, name='custom_login_page_admin'),
url(r'^admin/logout', your_custom_logout_view, name='custom_logout_view_admin'),
url(r'^admin/', admin.site.urls),
]
Create a custom subclass of AdminSite and overwrite the login() method. Something like this:
class CustomAdminSite(admin.AdminSite):
def login(self, request, extra_context=None):
if not request.user.is_authenticated:
# not authenticated, redirect to main login page
login_path = reverse('login')
return HttpResponseRedirect(login_path)
if self.has_permission(request):
# Already logged-in, redirect to admin index
index_path = reverse('admin:index', current_app=self.name)
return HttpResponseRedirect(index_path)
else:
# Logged in, but doesn't have required permissions
return render(...) # render a template with your error message
Follow the Django documentation on how to customize the AdminSite class.
Why you want to do that? Admin Page is for admin purposes, just dont access /admin/ path anymore or just remove admin from your urls.py, doign that you will not be able to access admin pages anymore...
But if you want to make your users access your django admin native pages using your custom login page, just make sure to tag your users with is_staff so they can access native django pages...
models.py
from django.contrib.auth.models import User
class CustomUser(User):
... # Your new fields
views.py
def create_user(request):
...
user, created = CustomUser.objects.get_or_created(
... # Your Custom + User Django fields
is_staff = True # This will allow this user to access the admin page
)
If you want allow all your users to access your django admin pages without need to use Django Login Page you can override your CustomUser model to set all users with is_staff
class CustomUser(User):
... # Your new fields
def save(self, *args, **kwargs):
if not self.id: # This indentify if the registry is new...
self.is_staff = True
super(CustomUser, self).save(*args, **kwargs)
Obs.: Make sure your User models extends the Django User Auth, there 2... one more complex and one simple, check the docs
https://docs.djangoproject.com/en/2.0/ref/contrib/auth/
All mentioned solutions here might do a good job, but my solution would be a little different: If you want to redirect to your default login page and hide the django-admin, sth. simple like this is a good workaround:
urlpatterns = [
path('admin/login/', RedirectView.as_view(pattern_name='account_login', permanent=True)),
]
Of course the target route (here account_login) can be changed as desired.
I prefer this approach:
on urls.py
from .settings import LOGIN_URL
from django.views.generic import RedirectView,
from django.urls import path, include
from django.contrib import admin
urlpatterns = [
path('admin/login/', RedirectView.as_view(url=LOGIN_URL)),
path('admin/', admin.site.urls),
....
]
To disable admin just remove url(r'^admin/', admin.site.urls), from your main urls.py. Another things to clean are 'django.contrib.admin' from INSTALLED_APPS.
A real easy way to accomplish this is by doing 2 things:
Head to your settings.py file and add: ADMIN_ENABLED = False
Head to your main urls.py file which should have something that looks like:
from django.urls import path, include
urlpatterns = [
# path('admin/', admin.site.urls),
path('', include("landing.urls")),
]
and comment out the path to admin like in the above snippet.
Cheers!

Reverse model admin custom URLs

Inside my admin.py file I have:
def get_urls(self):
urls = super(TextAdmin, self).get_urls()
my_urls = patterns('',
url(
r'customfunc1',
customfunc2,
name='customfunc23',
),
)
return my_urls + urls
Which will enable the following URL:
http://localhost:8000/admin/text/customfunc1
Which will execute function customfunc2. My question is now how would I reference this URL through doing reverse?
I tried:
reverse("admin:text_customfunc1")
reverse("admin:text_customfunc2")
reverse("admin:text_customfunc3")
reverse("text:customfunc1")
But none of those work.
You have name='customfunc23', and it is in the admin app, so you should use:
reverse('admin:customfunc23')

Return and link to homepage django

I have a project in DJANGO with this structure:
/
|---- core
|---- client
In client/views.py, I have the code:
class ClientDelete(DeleteView):
model = Cliente
success_url = reverse_lazy('cliente_list')
Where client_list is the HTML page on client/clients that lists all clients.
In core/views.py module, I have the function:
def homepage(request):
return render(request, 'home.html')
Where "home.html" is the homepage.
My main urls.py is something like this:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^cliente/', include('clientes.urls')),
url(r'^about/', aboutpage),
url(r'^$', homepage),
]
I need to return and make a link into client, core, and other apps to homepage. But when I try to return homepage into client.views.ClientDelete, the url on browser didn't redirect to home, but shows something like:
localhost:8000/client/home when I want back to localhost:8000.
What should I do?
Thank you.
First, it is useful to set names for urls:
url(r'^$', homepage, name='home')
So for your code you should do:
class ClientDelete(DeleteView):
model = Cliente
success_url = reverse_lazy('home')
if you want to be redirected to home page.
You can also use namespaces if you have different apps. So you will be able to do:
# redirect to home
success_url = reverse_lazy('home')
# redirect to clients list
success_url = reverse_lazy('clients:list')
To use it you need to make following changes:
url(r'^cliente/', include('clients.urls', namespace='clients'))
and set a name for urls inside clientes.urls.
Docs:
https://docs.djangoproject.com/es/1.9/topics/http/urls/#url-namespaces-and-included-urlconfs

Override AdminSite to append custom urls

I overrode default AdminSite class as described in manual, though it's too pure with information about this part over there.
My gs/admin.py file:
from django.contrib.admin import AdminSite
from django.conf.urls import patterns, url
from gs.views import *
class AdminSiteGs(AdminSite):
def get_urls(self):
urls = super(AdminSiteGs, self).get_urls()
urls += patterns('',
url(r'^my_admin_view/$', self.admin_view(my_admin_view))
)
return urls
admin_site_gs = AdminSiteGs()
gs it's my application and project name.
gs/urls.py file:
from django.conf.urls import patterns, include, url
from page import views
from gs.admin import admin_site_gs
urlpatterns = patterns('',
url(r'^admin/', include(admin_site_gs.urls)),
)
and I have application named page, where I place admin.py file:
from gs.admin import admin_site_gs
from page.models import Page, Menu
from django.contrib import admin
class PageAdmin(admin.ModelAdmin):
list_display = ('name', 'url', 'page_type')
class MenuAdmin(admin.ModelAdmin):
list_display = ('name', 'code')
admin_site_gs.register(Page, PageAdmin)
admin_site_gs.register(Menu, MenuAdmin)
So nothing here is working =( Neither /admin/my_admin view ( it returns 404 ), nor main admin page /admin. I don't see my models I registered in page/admin.py file.
It may sounds fun, but I tried all staff working in 3-4 hours =)) As you might guess I'm completely newbie both in Django and Python... All I want to know now is how to append custom URLs and views to my overriden class of AdminSite?
I removed autodiscover method, so now seems Django doesn't see nothing about file page/admin.py.
But the first question is more interesting, why I've had 404 error on trying to access the /admin/my_admin page ...
PS why my greeting at the beginning has been cutted o_O
According to the docs, any URL patterns you define for custom admin views must be occur before the admin patterns: https://docs.djangoproject.com/en/1.4/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_urls
Try:
def get_urls(self):
urls = super(AdminSiteGs, self).get_urls()
my_urls = patterns('',
url(r'^my_admin_view/$', self.admin_view(my_admin_view))
)
return my_urls + urls
You shouldn't need to include these patterns like this:
urlpatterns = patterns('',
url(r'^admin/', include(admin_site_gs.urls)), # not needed
)
In my case, I had to override the default 'add url' in order to redirect to a custom Django admin page when clicking '+Add' button in the admin.
So if I just override get_urls() in the way #Brandon said, it will return a list with a duplicate 'add' url (the custom one and the one retrieved from the super).
def get_urls(self):
info = self.model._meta.app_label, self.model._meta.model_name
urls = super(RetailerAdmin, self).get_urls()
# We need to remove the original 'add_url' in order to use the custom one.
urls.remove(urls[1])
custom_url = [
url(r'^batch/$', self.admin_site.admin_view(self.batch_upload_retailers),
name='%s_%s_add' % info),
]
return custom_url + urls
To solve this, I removed the original 'add' url (notice that the 'add' url is always in position 1).

Categories

Resources