Multiple Django admin sites

Throughout this chapter, you've learned the Django admin site is activated under the /admin/ url using django.contrib.admin.site.urls. In addition, the Django admin site also requires the definition of Django admin classes to be placed inside a Django project's app admin.py files and registered using one of the techniques described in listing 11-1 (e.g. django.contrib.admin.site.register(Store,StoreAdmin))

While this is the standard practice for almost all Django admin site installations, this process can differ for cases when you want or need to set up multiple Django admin sites. This of course begets the question 'Why would you want or need multiple Django admin sites ?'

Mulitple Django admin sites are helpful because they let you separate the access locations for different types of users or groups. For example, you can have a Django admin site designed to let employees perform CRUD operations across different models, while having a completely different Django admin site designed to let providers perform more limited CRUD operations across another set of models.

If you maintain a single Django admin site, creating a solution for multiple types of users and models can be very difficult as you only have user permissions to enforce CRUD operation access, as described in the previous section. With multiple Django admin sites, you can register models in one or both admin sites depending on your requirements.

The first step to create multiple Django admin sites is to create multiple instances of the django.contrib.admin.AdminSite class, as illustrated in listing 11-26

Listing 11-26. Django admin multiple sites accessible on different urls.

# urls.py (Main directory)
from django.conf.urls import include, url
from django.views.generic import TemplateView
from django.contrib import admin

admin.site.site_header = 'Coffeehouse general admin'

from coffeehouse.admin import employeeadmin, provideradmin

urlpatterns = [
url(r'^$',TemplateView.as_view(template_name='homepage.html'),name="homepage"),
url(r'^admin/', admin.site.urls),
url(r'^employeeadmin/', employeeadmin.urls),
url(r'^provideradmin/', provideradmin.urls),   
]

# admin.py (Main directory)
from django.contrib.admin import AdminSite

class EmployeeAdminSite(AdminSite):
    site_header = 'Coffeehouse Employee admin'

employeeadmin = EmployeeAdminSite(name='employeeadmin')

class ProviderAdminSite(AdminSite):
    site_header = 'Coffeehouse Provider admin'

provideradmin = ProviderAdminSite(name='provideradmin')

First, notice listing 11-26 declares the standard Django admin with the django.contrib.admin class in urls.py, including a custom site_header value to mount the Django admin on the standard /admin/ url. Next, two custom Django admin instances are configured on their own urls -- /employeeadmin/ and /provideradmin/ -- using a urls reference that corresponds to a custom django.contrib.admin.AdminSite class.

Both the EmployeeAdminSite and ProviderAdminSite custom Django admin site classes are defined in their own admin.py file in the top level directory of the project (i.e. alongside the main urls.py file). Notice how each of the custom Django admin site classes inherits its behavior from the django.contrib.admin.AdminSite class. Next, observe how each instance of the AdminSite classes in listing 11-26, also defines the site_header field to define a custom header for each Django admin site instance, just like it's done with the standard Django admin site.

At this juncture, if you visit either the /employeeadmin/ and /provideradmin/ urls for the custom Django admins, you'll access a main Django admin page like the one in figure 11-47. The reason you'll see an empty Django admin page in both cases, is because each custom Django admin site still doesn't have any models registered to it.

To register Django admin classes with a custom Django admin site, you can use any of the techniques already described in listing 11-1. The difference though is you must register a Django admin class with an instance of a specific Django admin site (e.g. employeeadmin, provideradmin) instead of the default django.contrib.admin class, as illustrated in listing 11-27.

Listing 11-27. Django admin class registration on multiple Django admin sites

# admin.py (stores app)
from django.contrib import admin
from coffeehouse.stores.models import Store,Amenity

class StoreAdmin(admin.ModelAdmin):
    search_fields = ['city','state']

# Default model registration on main Django admin
admin.site.register(Store, StoreAdmin)

# Model registration on custom Django admin named provideradmin 
from coffeehouse.admin import provideradmin

provideradmin.register(Store, StoreAdmin)

# admin.py (items app)
from django.contrib import admin
from coffeehouse.items.models import Menu

class MenuAdmin(admin.ModelAdmin):
    list_display = ['name','creator']
    
# Default model registration on main Django admin
admin.site.register(Menu, MenuAdmin)

# Model registration on custom Django admin named provideradmin 
from coffeehouse.admin import employeeadmin

employeeadmin.register(Menu, MenuAdmin)

Notice in listing 11-27, that in addition to the default Django admin class registration done through admin.site.register, the Store class is registered with the custom provideradmin Django admin class and the Menu class is registered with the custom employeeeadmin Django admin class, both of which are the custom Django admin classes declared in listing 11-26.

As you can see in listing 11-27, it's perfectly valid to register the same Django admin class on multiple Django admin sites, a process that allows you to selectively access certain models under different Django admin sites.

Caution Multiple Django admin sites don't preclude user permissions, authentication or url visibility. By default, all Django users can use the same credentials and are assigned the same permissions across multiple Django admin sites. This means it's up to you to enforce effective model permissions across all Django admin sites, limit model registration for each Django admin site, as well as avoid easy to guess Django admin urls to avoid unintended access.