How to Redesign the Django Admin with Bootstrap

Share this article

Hacking the Django Admin with Bootstrap

The Django administration site is great — fully-featured, easy to use, secure by design, rock solid … and somewhat ugly, which can be something of a downside when you want to integrate it with the look and feel of the rest of your website. Let’s sort that out.

If It Ain’t Broke …

The default Django admin
The default Django admin. (Source)

Say you’ve just prototyped a web app with Django and Vue.js. For a wide array of cases, using Django’s admin for back office purposes as is, and even handling it over to your client after appropriately setting permissions, is just fine. After all, it works perfectly well and it can be heavily customized with the built-in tools to cover many situations.

So again, why bother?

Reasons to Hack the Look and Feel of the Admin

However, there are a number of valid reasons to take integration a step further:

  • Branding: there’s nothing wrong in wanting the name and colors of your company instead of “Django administration” (and for the record, this is in compliance with Django’s BSD license).
  • Seamless integration between main site and admin: you might want to be able to transition between back office functionality while navigating the site, and vice versa, by having a common navigation bar.
  • Prettifying: while the admin looks okay, and it has even implemented responsive web design principles ever since v2 (it works well on both, mobile and desktop), there’s a lot a well-crafted style sheet can do to make it look better.
  • Bypass functionality: you might also just want to create custom dropdown menus for the admin, displaying the options that you actually use and hiding from the user interface what you don’t really need, which could make for a better user experience.

A Practical Example

For this example, and not to repeat ourselves, we’ll resume the simple publishing web application we started for the Prototyping a Web App with Django and Vue.js article.

In a nutshell:

  • a Django app with two models:
  • Article with fields name author (linked), content and slug
  • Author: with fields name and slug
  • A single view called frontend that queries all registries in both models.
  • A single template called template.
  • Implementation of Vue.js with Vue Router and Vuex for a reactive scalable interface.

We won’t particularly care for the Vue.js integration in this installment, and we won’t modify it here.

The Basic Template

Source

Django templates are very versatile and powerful, and can either be created at the app level (a component of the Django site) or at the site level, and can even override the templates that come with Django (which is what we’ll do here).

Bootstrap logo
Source

We created a basic template that links to Bootstrap‘s JavaScript and style sheet, and also its companion tools, jQuery and Popper.

Here’s the base template we’re using for the main site, not at all different from what we would normally use for any other Django site:

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">

    <title>Django and Vue.js</title>
  </head>
  <body class="bg-light">
    <div class="bg-white container">
      <h1>Prototyping a Web App with Django and Vue.js</h1>

      <!-- Content -->
    </div>

    <!-- Vue.js -->
    <script src="https://unpkg.com/vue"></script>
    <script src="https://unpkg.com/vue-router"></script>

    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
  </body>
</html>

Next, we’ll integrate this into the admin, and add a shared navigation bar across both ends — the main site and the back office!

Integrating the Main UI Template with the Admin

As mentioned, we can override templates, including those of the admin. However, because of Django’s design, and unsurprisingly, the main site and the back office are two different systems, each with its own templates, style sheets, and contrib packages. So even if they will be almost identical, we’ll need to maintain two different templates — one for the main UI, and one for the admin.

Enabling a Directory for Templates in General

First, we need to tell Django where we’ll store the hacked admin template in the base directory.

Se we’ll need to edit myproject/settings.py. firstly, find the TEMPLATES constant and this DIRS key:

'DIRS': [],

Change that code to this:

'DIRS': [os.path.join(BASE_DIR, 'templates')],

Wrapping the Admin Template (admin/base Hack)

If we just wanted to do cosmetic changes, like passing a custom style sheet to the admin, or removing/replacing its header, we could get along with that by just editing the admin/base_site template and skipping this current step altogether. However, if we want to go all the way and “wrap” the admin section as if it was contained within our main site, with the possibility to have a common header and footer, then keep reading.

We’ll need to copy Django’s admin/base.html to our templates directory in templates/admin/base.html, so that we can place our wrappers.

We’ll edit the code around the container section, so that it goes from this:

<!-- Container -->
<div id="container">
(...)
</div>
<!-- END Container -->

to this:

{% block bodyheader %}{% endblock %}

<!-- Container -->
<div id="container">
(...)
</div>
<!-- END Container -->

{% block bodyfooter %}{% endblock %}

And that’s all! We simply created bodyheader and bodyfooter block tags, so that we could inject the code that will wrap the admin on the next step.

Coding a Custom Admin Template (admin/base_site Hack)

Then, we’ll code the actual template in templates/admin/base_site.html (we’ll need to create the directories on the root of our project):

{% extends "admin/base_site.html" %}

{% block title %}Django with Bootstrap | Admin site{% endblock %}

{% block branding %}{% endblock %}
{% block breadcrumbs %}{% endblock %}

{% block bodyclass %}bg-light{% endblock %}

{% block extrastyle %}
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
    <style>
      #header, .breadcrumbs { display: none; }

      /* Bootstrap issues with admin */
      * { box-sizing: unset; }
      div.module caption { caption-side: top !important; }
      .collapse { display: block !important; }
    </style>
{% endblock %}

{% block bodyheader %}
    <div class="bg-white container">

      <div class="jumbotron">
        <h1 class="display-4">Hacking the Django Admin with Bootstrap</h1>
        <p class="lead">
          The <a ref="https://docs.djangoproject.com/en/dev/ref/contrib/admin/">Django administration site</a> is great—full-featured, easy to use, secure by design, rock solid… and somewhat ugly, which can be something of a downside when you want to integrate it with the look-and-feel of the rest of the website. Let’s sort that out.
        </p>
      </div>
{% endblock %}

{% block bodyfooter %}
    </div>

    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
{% endblock %}

Breakdown

Let’s try to explain what we’re doing here:

  1. We tell the template engine that we are “extending” the admin/base_site.html template, to effectively override some of its definitions.
  2. We make use of the title block to customize a title for the admin page being browsed.
  3. We empty the content of branding and breadcrumbs blocks, as we don’t really need them.
  4. We use the bodyclass block to set Bootstrap’s bg-light, as we did in the frontend template.
  5. We use the extrastyle block to embed Bootstrap, and some CSS code. a. Okay, #header, .breadcrumbs { display: none; } is something of a restatement of number 3; but it’s useful to know you can disable the branding and breadcrumbs sections both ways. b. There can be some issues when overlapping Bootstrap with Django’s CSS in the admin, so these are some fixes.
  6. Use the bodyheader and bodyfooter blocks to wrap the admin content.

Now that we have access to the admin template, we could further its style sheet, or just leave it at that with a shared style with the main UI.

Caveats

We’re maintaining two different templates (main UI and admin) to do essentially the same presentation. Admittedly, this isn’t ideal, as we’re explicitly breaking one of the maxims of software development: don’t repeat yourself (DRY).

As we commented, this is because the Django admin has been designed to be detached from the main UI. And there’s nothing wrong with that, just as there isn’t anything wrong with thinking out of the box. But yes, that forces us to use two templates with nearly the same content.

Actually, in principle we could design a template pattern that included that navbar and other common elements from the main UI and the admin, and reuse them from that single source; but at this point, and for the purpose of this article, that approach would be a little overkill. Anyway, I’ll leave the idea planted for you. 😉

Making a Shared Navigation Bar

Now that the main UI and the admin site look nearly the same, we can go further in our integration and make a common navigation experience … and even further, present some admin options right on the main menu!

Here’s the snippet for the navbar:

<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <ul class="navbar-nav mr-auto">
    <li class="nav-item">
      <a
        class="nav-link text-primary"
        href="/author/"
      >
        Go to Authors
      </a>
    </li>
    <li class="nav-item">
      <a
        class="nav-link text-primary"
        href="/article/"
      >
        Go to Articles
      </a>
    </li>
    {% if user.is_authenticated %}
    <li class="nav-item dropdown">
      <a
        aria-expanded="false"
        aria-haspopup="true"
        class="font-weight-bold nav-link text-primary dropdown-toggle"
        data-toggle="dropdown"
        href="#"
        role="button"
      >
        Admin
      </a>
      <div class="dropdown-menu">
        <a class="dropdown-item" href="/admin/myapp/author/">
          Manage authors
        </a>
        <a class="dropdown-item" href="/admin/myapp/article/">
          Manage articles
        </a>
      </div>
    </li>
    {% endif %}
  </ul>
</nav>

Notice the dropdown-menu section, that will take care of presenting an admin menu (see Bootstrap’s Navbar component for more info).

We also do a conditional check with {% if user.is_authenticated %} /{% endif %}, to decide if we show the admin menu or not.

Lastly, remember that, since we’re now maintaining two different main templates, we’ll need to add the HTML code of the navbar to both, myapp/templates/myapp/tempalte.html and templates/admin/base_site.html.

Extra: the Admin Login Screen

The admin site has been taken care of, but there is still a loose end: the login screen.

Now we could turn something like this:

Admin login
Source

… into something like this:

New login layout

We can accomplish something closer to that by creating the following template in templtes/admin/login.html:

{% extends "admin/login.html" %}

{% load i18n static %}

{% block extrastyle %}
{{ block.super }}
<style>
#header {
  background-color: transparent !important;
}
</style>
{% endblock %}

{% block branding %}
<h1>
  <span style="color: #57C5A5 !important">ActionPlanNow.com</span>
  <br />
  <small>{% block head_title %}{% endblock %}</small>
</h1>
{% endblock %}

{% block content_title %}
<p class="lead" style="font-size: larger">
A Simple Tool for Leaders, Coaches, and Counselors.
</p>
{% endblock %}

Breakdown

What we’re doing here:

  1. The {{ block.super }} tag is there to tell the template engine that we’re not overriding the content of extrastyle (that we defined in the templates/admin/base_site.html template) but that we’re simply appending content to it (see template inheritance for more info).
  2. The branding block allows us to change the “Django administration” header to something more interesting.
  3. We get rid of the head_title block by setting an empty definition.
  4. We use the content_title block to add some extra info.

Some Considerations

jquery logo
Source

Just like Bootstrap, the Django admin site also ships its own bundle of jQuery, but fortunately the Django developers thought this through and to avoid conflicts with user-supplied scripts and libraries, Django’s jQuery is namespaced as django.jQuery. So we can include your own copy (as we have done) safely.

Be careful when going crazy with class definitions in your main style sheet, as that will also impact the admin site, affecting its functionality in unexpected ways. In that event, you can always see what’s going on with your browser debugging tools, such as Chrome DevTools, Firefox Developer Tools (particularly Page Inspector), or Safari Developer Tools.

Demo and Full Code

This implementation we discussed here will look like this:

You can navigate all of the project code in my GitHub repository, luzdealba / djangovuejs.

Wrap Up

While some might claim — quite reasonably — that there isn’t much need to alter Django’s admin appearance, it’s also true that smoothly integrating the different endpoints of a site is a fine hack for improved UX, as it can provide seamless transition between the two, and even a more controlled navigation of the admin.

And doing so isn’t all that difficult. What you need to pay attention to is how you wrap the admin, and also how you mix third-party libraries with your own JavaScript code and style sheets. Fortunately, you can very easily integrate some into the admin, some into the rest of the main site, and some into both.

Hopefully you’ve got some ideas about how you can further customize Django in ways that weren’t that evident!

If you need an excuse to build a web app just so you can play with the Django admin, check out last week’s tutorial on prototyping a web app with Django and Vue.js — it’s a tonne of fun. And if you want to take your Django skills further, the SitePoint Premium library has heaps of resources for you.

Frequently Asked Questions (FAQs) on Customizing Django Admin with Bootstrap

What are the benefits of customizing Django Admin with Bootstrap?

Customizing Django Admin with Bootstrap offers several benefits. Firstly, it enhances the visual appeal of your admin interface, making it more user-friendly and intuitive. Bootstrap is a popular front-end framework that provides a variety of design templates for typography, forms, buttons, and other interface components. By integrating it with Django Admin, you can leverage these templates to create a more visually appealing and functional admin interface. Secondly, it allows you to add custom functionalities to your admin interface. For instance, you can add custom actions, filters, and forms to improve the usability of your admin interface. Lastly, it can improve the responsiveness of your admin interface, making it more accessible on different devices and screen sizes.

How can I add custom actions to Django Admin?

Django Admin allows you to add custom actions that can be performed on selected objects. To add a custom action, you need to define a function that performs the desired action on the selected objects. This function should take three parameters: the model admin, the request, and a queryset of the selected objects. Once you’ve defined this function, you can add it to the ‘actions’ attribute of your model admin. This will make the action available in the action dropdown on the admin change list page.

Can I customize the look and feel of Django Admin using Bootstrap?

Yes, you can customize the look and feel of Django Admin using Bootstrap. Bootstrap is a front-end framework that provides a variety of design templates for typography, forms, buttons, and other interface components. By integrating it with Django Admin, you can leverage these templates to create a more visually appealing and functional admin interface. You can customize the colors, fonts, layout, and other design elements of your admin interface to match your brand identity or personal preferences.

How can I add custom filters to Django Admin?

Django Admin allows you to add custom filters that can be used to filter the objects displayed on the admin change list page. To add a custom filter, you need to define a subclass of django.contrib.admin.SimpleListFilter. This subclass should define two methods: lookups and queryset. The lookups method should return a list of tuples, each representing a filter option. The queryset method should return a filtered queryset based on the selected filter option. Once you’ve defined this subclass, you can add it to the ‘list_filter’ attribute of your model admin.

Can I use Bootstrap with Django Admin without any additional packages?

While it’s possible to use Bootstrap with Django Admin without any additional packages, it’s generally easier and more efficient to use a package like django-admin-bootstrap. This package provides a Bootstrap-based theme for Django Admin, making it easier to integrate Bootstrap with Django Admin. It also provides additional features like responsive design and custom form rendering, which can further enhance the usability and functionality of your admin interface.

How can I customize the form fields in Django Admin?

Django Admin allows you to customize the form fields used to create or edit objects. To customize a form field, you need to override the ‘formfield_for_dbfield’ method of your model admin. This method should return a form field instance that will be used for the specified database field. You can customize the form field’s attributes, widgets, and validation behavior to suit your needs.

Can I add custom views to Django Admin?

Yes, you can add custom views to Django Admin. To add a custom view, you need to define a method in your model admin that handles the view logic. This method should take a request as its only parameter and return a response. You can then map this method to a URL by adding a URL pattern to the ‘get_urls’ method of your model admin. This will make the view accessible from the admin interface.

How can I customize the list display in Django Admin?

Django Admin allows you to customize the list display, which is the table of objects displayed on the admin change list page. To customize the list display, you can set the ‘list_display’ attribute of your model admin to a list of field names that you want to display. You can also include method names in this list, which will call the corresponding method on each object and display the result.

Can I use Django Admin for complex database models?

Yes, Django Admin is designed to handle complex database models. It provides a variety of features that can help you manage complex data structures, such as inline editing of related objects, custom form fields, and custom actions. However, for very complex data structures or advanced database operations, you might need to extend Django Admin with custom views, forms, or actions.

How can I improve the performance of Django Admin?

There are several ways to improve the performance of Django Admin. One way is to optimize your database queries. Django Admin automatically generates database queries based on your model definitions and admin options. However, these queries can sometimes be inefficient, especially for complex data structures or large datasets. By customizing your admin options and using Django’s database optimization features, you can significantly reduce the number of database queries and improve the performance of your admin interface. Another way is to use caching. Django provides a robust caching framework that you can use to cache the results of expensive operations or frequently accessed data. By using caching, you can reduce the load on your database and improve the responsiveness of your admin interface.

Lucero del AlbaLucero del Alba
View Author

Lucero is a programmer and entrepreneur with a feel for Python, data science and DevOps. Raised in Buenos Aires, Argentina, he's a musician who loves languages (those you use to talk to people) and dancing.

bootstrapdjangodjango adminpython
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week