36
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.
27
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
- [Django]-How to use "get_or_create()" in Django?
- [Django]-405 "Method POST is not allowed" in Django REST framework
- [Django]-Django: Group by date (day, month, year)
- [Django]-Unit testing with django-celery?
- [Django]-Using IntellijIdea within an existing virtualenv
- [Django]-Django+Postgres: "current transaction is aborted, commands ignored until end of transaction block"
6
If you want to create a custom page just to place there an arbitrary form to handle user input, you may give django-etc a try. There’s etc.admin.CustomModelPage
you can use:
# admin.py
from etc.admin import CustomModelPage
class MyPage(CustomModelPage):
title = 'My custom page' # set page title
# Define some fields you want to proccess data from.
my_field = models.CharField('some title', max_length=10)
def save(self):
# Here implement data handling.
super().save()
# Register the page within Django admin.
MyPage.register()
- [Django]-Serialize queryset in Django rest framework
- [Django]-How do I drop a table from SQLite3 in DJango?
- [Django]-Iterating over related objects in Django: loop over query set or use one-liner select_related (or prefetch_related)
5
Here’s an example of everything that should be needed (as of Django 1.6) for a custom admin page that is linked to from a button next to the “History” button in the top right of an object’s detail page:
- [Django]-Django-admin.py makemessages not working
- [Django]-How to access array elements in a Django template?
- [Django]-Referencing multiple submit buttons in django
5
Full example:
from django.urls import path
from django.contrib import admin
from django.db import models
class DummyModel(models.Model):
class Meta:
verbose_name = 'Link to my shiny custom view'
app_label = 'users' # or another app to put your custom view
@admin.register(DummyModel)
class DummyModelAdmin(admin.ModelAdmin):
def get_urls(self):
view_name = '{}_{}_changelist'.format(
DummyModel._meta.app_label, DummyModel._meta.model_name)
return [
path('my_view/', MyCustomView.as_view(), name=view_name)
]
With this approach Django’s makemigrations command will create DB migration to create table for DummyModel.
- [Django]-Open the file in universal-newline mode using the CSV Django module
- [Django]-CSS styling in Django forms
- [Django]-How to export virtualenv?
2
Extending the AdminSite
class worked best for me, as per django’s documentation. This solution protects the page(s) under the admin site login mechanism, and setting it up is easier than it may look:
- Where you have other admin code (eg.
myapp/admin.py
), extend the default class:
from django.contrib.admin import AdminSite
class CustomAdminSite(AdminSite):
def get_urls(self):
custom_urls = [
path('admin/preferences/', self.admin_view(views.my_view)),
]
admin_urls = super().get_urls()
return custom_urls + admin_urls # custom urls must be at the beginning
site = CustomAdminSite()
# you can register your models on this site object as usual, if needed
site.register(Model, ModelAdmin)
- Implement the view
def my_view(request):
return render(request, 'admin/preferences/preferences.html')
- Use that admin site in
urls.py
, instead of the default one
from myapp import admin
# now use admin.site as you would use the default django one
urlpatterns = [
# ...
path('admin/', admin.site.urls),
# ...
]
- [Django]-When should I use a custom Manager versus a custom QuerySet in Django?
- [Django]-AngularJS with Django – Conflicting template tags
- [Django]-Django ignores router when running tests?
0
If you want to hook a page into the existing admin site, then you can do the following, which is based on #arnaud-p’s answer above. Arnaud’s answer didn’t work for me, as subclassing adminsite’s get_url function lost access to existing admin pages until I added the registry as follows.
Using the following method, your additional pages will require staff access, and you don’t need to change your urls.py, so this is great for making admin pages for apps etc… You can pass each_context in the view in order to get permissions etc.
works for django 3.2.9
In admin.py
from django.contrib import admin
from django.urls import path
from . import views
class CustomAdminSite(admin.AdminSite):
def get_urls(self):
self._registry = admin.site._registry
admin_urls = super().get_urls()
custom_urls = [
path('preferences/', views.Preferences.as_view(admin=self), name="preferences"),
]
return custom_urls + admin_urls # custom urls must be at the beginning
def get(self):
request.current_app == self.name
return super().get(request)
def get_app_list(self, request):
app_list = super().get_app_list(request)
app_list += [
{
"name": "My Custom Preferences App",
"app_label": "Preferences",
# "app_url": "/admin/test_view",
"models": [
{
"name": "Preferences",
"object_name": "preferences",
"admin_url": "/admin/preferences",
"view_only": True,
}
],
}
]
return app_list
site = CustomAdminSite()
the view…
class Preferences(views.generic.ListView):
admin = {}
def get(self, request):
ctx = self.admin.each_context(request)
return render(request, 'admin/preferences/preferences.html', ctx)
the template…
{% extends "admin/base_site.html" %}
{% block content %}
...HELLO WORLD!
{% endblock %}
- [Django]-Why is assertDictEqual needed if dicts can be compared by `==`?
- [Django]-Page not found 404 Django media files
- [Django]-Django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module: No module named MySQLdb