alandarev
alandarev

Reputation: 8635

Add context to every Django Admin page

How do I add extra context to all admin webpages?

I use default Django Admin for my admin part of a site.

Here is an url entry for admin:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

And my apps register their standard view models using:

admin.site.register(Tag, TagAdmin)

My problem, is that I want to display an extra field in admin template header bar and I have no idea how to add this extra context.

My first bet was adding it in url patterns like below:

urlpatterns = [
    url(r'^admin/', admin.site.urls, {'mycontext': '123'}),
]

But that gives an error:

TypeError at /admin/tickets/event/4/change/

change_view() got an unexpected keyword argument 'mycontext'

Can you give any suggestion? I really do not want to modify every AdminModel class I have to insert this context, as I need it on every admin page.

Thanks.

Upvotes: 17

Views: 6805

Answers (3)

pphysch
pphysch

Reputation: 309

You can monkey-patch the default admin site like so:

Top level urls.py:

from django.contrib import admin
from django.urls import include, path

...

# Store a reference to the default each_context so we don't cause an infinite loop when we override it.
base_admin_context = admin.site.each_context

def custom_admin_context(request):
    context = base_admin_context(request)
    
    # Do anything we want with the context
    # Example: adding a custom sidebar nav section at the top
    context["available_apps"].insert(
        0,
        {
            "name": "Extra stuff",
            "app_url": "/admin/extra/",
            "has_module_perms": True,
            "models": [
                {
                    "object_name": None,
                    "name": "A custom admin dashboard",
                    "admin_url": "/admin/extra/dashboard",
                }
            ],
        },
    )
    return context

admin.site.each_context = custom_admin_context

...

urlpatterns = [...]

If you are already overriding other default admin.site values, this can be a low-complexity solution.

Upvotes: 0

frnhr
frnhr

Reputation: 12903

Another technique, more complex but allows different context per request (probably unavailable at OP time):

my_project/admin.py (create if missing)

from django.contrib import admin
from django.contrib.admin.apps import AdminConfig


class MyAdminConfig(AdminConfig):
    default_site = 'my_project.admin.MyAdminSite'


class MyAdminSite(admin.AdminSite):
    def each_context(self, request):
        context = super().each_context(request)
        context.update({
            "whatever": "this is",
            "just a": "dict",
        })
        return context

settings.py

INSTALLED_APPS = [
    ...
    'my_project.admin.MyAdminConfig',  # replaces 'django.contrib.admin'
    ...

The replace / extend admin class code is taken from the official docs except this is all in one file.

Upvotes: 5

alandarev
alandarev

Reputation: 8635

Found the solution, url registration has to be:

urlpatterns = [
    url(r'^admin/', admin.site.urls, {'extra_context': {'mycontext': '123'}}),
]

Its a context dictionary inside of a dictionary with 'extra_context' as a key.

Upvotes: 9

Related Questions