hmmm. Thanks for your help everyone. The solution I have come up ( with your help ofcourse :) is as follows:
I have two custom templates:
my_model_list.html
my_model_detail.html
Under views.py:
class MyModel(object):
# ... Access other models
# ... process / normalise data
# ... store data
@staff_member_required
def my_model_list_view(request) #show list of all objects
#. . . create objects of MyModel . . .
#. . . call their processing methods . . .
#. . . store in context variable . . .
r = render_to_response('admin/myapp/my_model_list.html', context, RequestContext(request))
return HttpResponse(r)
@staff_member_required
def my_model_detail_view(request, row_id) # Shows one row (all values in the object) in detail
#. . . create object of MyModel . . .
#. . . call it's methods . . .
#. . . store in context variable . . .
r = render_to_response('admin/myapp/my_model_detail.html', context, RequestContext(request))
return HttpResponse(r)
Under the main django urls.py:
urlpatterns = patterns(
'',
(r'^admin/myapp/mymodel/$', my_model_list_view),
(r'^admin/myapp/mymodel/(\d+)/$', my_model_detail_view),
( r'^admin/', include( admin.site.urls ) )
)
Answer from sysasa on Stack Overflowhmmm. Thanks for your help everyone. The solution I have come up ( with your help ofcourse :) is as follows:
I have two custom templates:
my_model_list.html
my_model_detail.html
Under views.py:
class MyModel(object):
# ... Access other models
# ... process / normalise data
# ... store data
@staff_member_required
def my_model_list_view(request) #show list of all objects
#. . . create objects of MyModel . . .
#. . . call their processing methods . . .
#. . . store in context variable . . .
r = render_to_response('admin/myapp/my_model_list.html', context, RequestContext(request))
return HttpResponse(r)
@staff_member_required
def my_model_detail_view(request, row_id) # Shows one row (all values in the object) in detail
#. . . create object of MyModel . . .
#. . . call it's methods . . .
#. . . store in context variable . . .
r = render_to_response('admin/myapp/my_model_detail.html', context, RequestContext(request))
return HttpResponse(r)
Under the main django urls.py:
urlpatterns = patterns(
'',
(r'^admin/myapp/mymodel/$', my_model_list_view),
(r'^admin/myapp/mymodel/(\d+)/$', my_model_detail_view),
( r'^admin/', include( admin.site.urls ) )
)
You can add your views directly to the AdminSite object, rather than to any particular ModelAdmin subclass which you then register.
The default AdminSite is accessed via django.contrib.admin.site, which is what you call register and autodiscover on. Instead of using this, you could create your own subclass and add your own views to it, and then register your models against that rather than the default one.
You need to add your admin URL before the URL patterns of the admin itself:
urlpatterns = patterns('',
url(r'^admin/preferences/$', TemplateView.as_view(template_name='admin/preferences/preferences.html')),
url(r'^admin/', include('django.contrib.admin.urls')),
)
This way the URL won't be processed by Django's admin.
Years go by and still a relevant answer to this can be posted.
Using Django 1.10+ you can do:
security/admin.py (this is your app's admin file)
from django.contrib import admin
from django.conf.urls import url
from django.template.response import TemplateResponse
from security.models import Security
@admin.register(Security)
class SecurityAdmin(admin.ModelAdmin):
def get_urls(self):
# get the default urls
urls = super(SecurityAdmin, self).get_urls()
# define security urls
security_urls = [
url(r'^configuration/$', self.admin_site.admin_view(self.security_configuration))
# Add here more urls if you want following same logic
]
# Make sure here you place your added urls first than the admin default urls
return security_urls + urls
# Your view definition fn
def security_configuration(self, request):
context = dict(
self.admin_site.each_context(request), # Include common variables for rendering the admin template.
something="test",
)
return TemplateResponse(request, "configuration.html", context)
security/templates/configuration.html
{% extends "admin/base_site.html" %}
{% block content %}
...
{% endblock %}
See Official ModelAdmin.get_urls description (make sure you select proper Django version, this code is valid for 1.10 above)
- Note the use of get_urls() above.
- This new admin page will be accessible under: https://localhost:8000/admin/security/configuration/
- This page will be protected under admin login area
python - Add custom page to django admin without a model - Stack Overflow
Django admin, section without "model"? - Stack Overflow
Django how to add admin page without using model - Stack Overflow
Custom admin page
Videos
I’m trying to create a custom view instead of just model pages, it looks like all implementation for admin is closely tied to the models themselves.
The admin comes prebuilt with search, change form, autocomplete and plenty of apps that add functionality on top of it as well as builtin permissions support.
I find it purely logical that i do not want to be rewriting all that if i can extend the admin with just one or two views to satisfy my requirements for internal use.
Are there libs that extend or rethink the admin ?
» pip install django-nonmodel-admin
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.
You have 3 options here:
Using third-party packages which provide menu
This is pretty straight forward, there are some good packages out there which support menu for admin, and some way to add your item to the menu.
An example of a 3rd party package would be django-admin-tools (last updated Dec 2021, checked April 2023). The drawback is that it is a bit hard to learn. Another option would be to use django-adminplus (last updated Oct 2019, checked April 2023) but at the time of writing this, it does not support Django 2.2.
Hacking with django admin templates
You can always extend admin templates and override the parts you want, as mentioned in @Sardorbek answer, you can copy some parts from admin template and change them the way you want.
Using custom admin site
If your views are supposed to only action on admin site, then you can extend adminsite (and maybe change the default), beside from adding links to template, you should use this method to define your admin-only views as it's easier to check for permissions this way.
Considering you already extended adminsite, now you can use the previous methods to add your link to template, or even extend get_app_list method, example:
class MyAdminSite(admin.AdminSite):
def get_app_list(self, request):
app_list = super().get_app_list(request)
app_list += [
{
"name": "My Custom App",
"app_label": "my_test_app",
# "app_url": "/admin/test_view",
"models": [
{
"name": "tcptraceroute",
"object_name": "tcptraceroute",
"admin_url": "/admin/test_view",
"view_only": True,
}
],
}
]
return app_list
You can also check if current staff user can access to module before you show them the links.
It will look like this at then end:

Problem here that your div is not inside main-content. I suggest extending admin/index.html
Put in app/templates/admin/index.html
{% extends "admin/index.html" %}
{% load i18n static %}
{% block content %}
<div id="content-main">
{% if app_list %}
{% for app in app_list %}
<div class="app-{{ app.app_label }} module">
<table>
<caption>
<a href="{{ app.app_url }}" class="section" title="{% blocktrans with name=app.name %}Models in the {{ name }} application{% endblocktrans %}">{{ app.name }}</a>
</caption>
{% for model in app.models %}
<tr class="model-{{ model.object_name|lower }}">
{% if model.admin_url %}
<th scope="row"><a href="{{ model.admin_url }}">{{ model.name }}</a></th>
{% else %}
<th scope="row">{{ model.name }}</th>
{% endif %}
{% if model.add_url %}
<td><a href="{{ model.add_url }}" class="addlink">{% trans 'Add' %}</a></td>
{% else %}
<td> </td>
{% endif %}
{% if model.admin_url %}
{% if model.view_only %}
<td><a href="{{ model.admin_url }}" class="viewlink">{% trans 'View' %}</a></td>
{% else %}
<td><a href="{{ model.admin_url }}" class="changelink">{% trans 'Change' %}</a></td>
{% endif %}
{% else %}
<td> </td>
{% endif %}
</tr>
{% endfor %}
</table>
</div>
{% endfor %}
<!-- here you could put your div -->
<div class="app-sonstiges module">
....
</div>
<!-- here you could put your div -->
{% else %}
<p>{% trans "You don't have permission to view or edit anything." %}</p>
{% endif %}
</div>
{% endblock %}
The another approach is to add custom app to app_list. But it is far more ugly. So I suggest overriding template.
I assume you are overriding get_urls in AdminSite.
I think there might be a simpler way than writing custom ORMS to get the admin integration you want. I used it in an app that allows managing Webfaction email accounts via their Control Panel API.
Take a look at models.py, admin.py and urls.py here: django-webfaction
To create an entry on the admin index page use a dummy model that has managed=False
Register that model with the admin.
You can then intercept the admin urls and direct them to your own views.
This makes sense if the add/edit/delete actions the admin provides make sense for your app. Otherwise you are better off overriding the admin index or changelist templates to include your own custom actions
The real power of the contrib.admin is django Forms. In essence, the admin tool is basically auto-generating a Form to match a Model with a little bit of urls.py routing thrown in. In the end it would probably just be easier to use django Forms apart from the admin tool.