Home >Technology peripherals >It Industry >How to Redesign & Customize 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.
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?
However, there are a number of valid reasons to take integration a step further:
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:
We won’t particularly care for the Vue.js integration in this installment, and we won’t modify it here.
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).
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:
<span><span><!doctype html></span> </span><span><span><span><html</span> lang<span>="en"</span>></span> </span> <span><span><span><head</span>></span> </span> <span><!-- Required meta tags --> </span> <span><span><span><meta</span> charset<span>="utf-8"</span>></span> </span> <span><span><span><meta</span> name<span>="viewport"</span> content<span>="width=device-width, initial-scale=1, shrink-to-fit=no"</span>></span> </span> <span><!-- Bootstrap CSS --> </span> <span><span><span><link</span> rel<span>="stylesheet"</span> href<span>="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"</span> integrity<span>="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"</span> crossorigin<span>="anonymous"</span>></span> </span> <span><span><span><title</span>></span>Django and Vue.js<span><span></title</span>></span> </span> <span><span><span></head</span>></span> </span> <span><span><span><body</span> class<span>="bg-light"</span>></span> </span> <span><span><span><div</span> class<span>="bg-white container"</span>></span> </span> <span><span><span><h1</span>></span>Prototyping a Web App with Django and Vue.js<span><span></h1</span>></span> </span> <span><!-- Content --> </span> <span><span><span></div</span>></span> </span> <span><!-- Vue.js --> </span> <span><span><span><script</span> src<span>="https://unpkg.com/vue"</span>></span><span><span></script</span>></span> </span> <span><span><span><script</span> src<span>="https://unpkg.com/vue-router"</span>></span><span><span></script</span>></span> </span> <span><!-- jQuery first, then Popper.js, then Bootstrap JS --> </span> <span><span><span><script</span> src<span>="https://code.jquery.com/jquery-3.4.1.slim.min.js"</span> integrity<span>="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"</span> crossorigin<span>="anonymous"</span>></span><span><span></script</span>></span> </span> <span><span><span><script</span> src<span>="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"</span> integrity<span>="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"</span> crossorigin<span>="anonymous"</span>></span><span><span></script</span>></span> </span> <span><span><span><script</span> src<span>="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"</span> integrity<span>="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"</span> crossorigin<span>="anonymous"</span>></span><span><span></script</span>></span> </span> <span><span><span></body</span>></span> </span><span><span><span></html</span>></span> </span>
Next, we’ll integrate this into the admin, and add a shared navigation bar across both ends — the main site and the back office!
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.
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:
<span><span><!doctype html></span> </span><span><span><span><html</span> lang<span>="en"</span>></span> </span> <span><span><span><head</span>></span> </span> <span><!-- Required meta tags --> </span> <span><span><span><meta</span> charset<span>="utf-8"</span>></span> </span> <span><span><span><meta</span> name<span>="viewport"</span> content<span>="width=device-width, initial-scale=1, shrink-to-fit=no"</span>></span> </span> <span><!-- Bootstrap CSS --> </span> <span><span><span><link</span> rel<span>="stylesheet"</span> href<span>="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"</span> integrity<span>="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"</span> crossorigin<span>="anonymous"</span>></span> </span> <span><span><span><title</span>></span>Django and Vue.js<span><span></title</span>></span> </span> <span><span><span></head</span>></span> </span> <span><span><span><body</span> class<span>="bg-light"</span>></span> </span> <span><span><span><div</span> class<span>="bg-white container"</span>></span> </span> <span><span><span><h1</span>></span>Prototyping a Web App with Django and Vue.js<span><span></h1</span>></span> </span> <span><!-- Content --> </span> <span><span><span></div</span>></span> </span> <span><!-- Vue.js --> </span> <span><span><span><script</span> src<span>="https://unpkg.com/vue"</span>></span><span><span></script</span>></span> </span> <span><span><span><script</span> src<span>="https://unpkg.com/vue-router"</span>></span><span><span></script</span>></span> </span> <span><!-- jQuery first, then Popper.js, then Bootstrap JS --> </span> <span><span><span><script</span> src<span>="https://code.jquery.com/jquery-3.4.1.slim.min.js"</span> integrity<span>="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"</span> crossorigin<span>="anonymous"</span>></span><span><span></script</span>></span> </span> <span><span><span><script</span> src<span>="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"</span> integrity<span>="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"</span> crossorigin<span>="anonymous"</span>></span><span><span></script</span>></span> </span> <span><span><span><script</span> src<span>="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"</span> integrity<span>="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"</span> crossorigin<span>="anonymous"</span>></span><span><span></script</span>></span> </span> <span><span><span></body</span>></span> </span><span><span><span></html</span>></span> </span>
Change that code to this:
<span>'DIRS': [], </span>
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:
<span>'DIRS': [os.path.join(BASE_DIR, 'templates')], </span>
to this:
<span><!-- Container --> </span><span><span><span><div</span> id<span>="container"</span>></span> </span>(...) <span><span><span></div</span>></span> </span><span><!-- END Container --> </span>
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.
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):
{% block bodyheader %}{% endblock %} <span><!-- Container --> </span><span><span><span><div</span> id<span>="container"</span>></span> </span>(...) <span><span><span></div</span>></span> </span><span><!-- END Container --> </span> {% block bodyfooter %}{% endblock %}
Let’s try to explain what we’re doing here:
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.
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. ?
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:
<span><span><!doctype html></span> </span><span><span><span><html</span> lang<span>="en"</span>></span> </span> <span><span><span><head</span>></span> </span> <span><!-- Required meta tags --> </span> <span><span><span><meta</span> charset<span>="utf-8"</span>></span> </span> <span><span><span><meta</span> name<span>="viewport"</span> content<span>="width=device-width, initial-scale=1, shrink-to-fit=no"</span>></span> </span> <span><!-- Bootstrap CSS --> </span> <span><span><span><link</span> rel<span>="stylesheet"</span> href<span>="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"</span> integrity<span>="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"</span> crossorigin<span>="anonymous"</span>></span> </span> <span><span><span><title</span>></span>Django and Vue.js<span><span></title</span>></span> </span> <span><span><span></head</span>></span> </span> <span><span><span><body</span> class<span>="bg-light"</span>></span> </span> <span><span><span><div</span> class<span>="bg-white container"</span>></span> </span> <span><span><span><h1</span>></span>Prototyping a Web App with Django and Vue.js<span><span></h1</span>></span> </span> <span><!-- Content --> </span> <span><span><span></div</span>></span> </span> <span><!-- Vue.js --> </span> <span><span><span><script</span> src<span>="https://unpkg.com/vue"</span>></span><span><span></script</span>></span> </span> <span><span><span><script</span> src<span>="https://unpkg.com/vue-router"</span>></span><span><span></script</span>></span> </span> <span><!-- jQuery first, then Popper.js, then Bootstrap JS --> </span> <span><span><span><script</span> src<span>="https://code.jquery.com/jquery-3.4.1.slim.min.js"</span> integrity<span>="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"</span> crossorigin<span>="anonymous"</span>></span><span><span></script</span>></span> </span> <span><span><span><script</span> src<span>="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"</span> integrity<span>="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"</span> crossorigin<span>="anonymous"</span>></span><span><span></script</span>></span> </span> <span><span><span><script</span> src<span>="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"</span> integrity<span>="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"</span> crossorigin<span>="anonymous"</span>></span><span><span></script</span>></span> </span> <span><span><span></body</span>></span> </span><span><span><span></html</span>></span> </span>
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.
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:
… into something like this:
We can accomplish something closer to that by creating the following template in templtes/admin/login.html:
<span><span><!doctype html></span> </span><span><span><span><html</span> lang<span>="en"</span>></span> </span> <span><span><span><head</span>></span> </span> <span><!-- Required meta tags --> </span> <span><span><span><meta</span> charset<span>="utf-8"</span>></span> </span> <span><span><span><meta</span> name<span>="viewport"</span> content<span>="width=device-width, initial-scale=1, shrink-to-fit=no"</span>></span> </span> <span><!-- Bootstrap CSS --> </span> <span><span><span><link</span> rel<span>="stylesheet"</span> href<span>="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"</span> integrity<span>="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"</span> crossorigin<span>="anonymous"</span>></span> </span> <span><span><span><title</span>></span>Django and Vue.js<span><span></title</span>></span> </span> <span><span><span></head</span>></span> </span> <span><span><span><body</span> class<span>="bg-light"</span>></span> </span> <span><span><span><div</span> class<span>="bg-white container"</span>></span> </span> <span><span><span><h1</span>></span>Prototyping a Web App with Django and Vue.js<span><span></h1</span>></span> </span> <span><!-- Content --> </span> <span><span><span></div</span>></span> </span> <span><!-- Vue.js --> </span> <span><span><span><script</span> src<span>="https://unpkg.com/vue"</span>></span><span><span></script</span>></span> </span> <span><span><span><script</span> src<span>="https://unpkg.com/vue-router"</span>></span><span><span></script</span>></span> </span> <span><!-- jQuery first, then Popper.js, then Bootstrap JS --> </span> <span><span><span><script</span> src<span>="https://code.jquery.com/jquery-3.4.1.slim.min.js"</span> integrity<span>="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"</span> crossorigin<span>="anonymous"</span>></span><span><span></script</span>></span> </span> <span><span><span><script</span> src<span>="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"</span> integrity<span>="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"</span> crossorigin<span>="anonymous"</span>></span><span><span></script</span>></span> </span> <span><span><span><script</span> src<span>="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"</span> integrity<span>="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"</span> crossorigin<span>="anonymous"</span>></span><span><span></script</span>></span> </span> <span><span><span></body</span>></span> </span><span><span><span></html</span>></span> </span>
What we’re doing here:
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.
This implementation we discussed here will look like this:
You can navigate all of the project code in my GitHub repository, luzdealba / djangovuejs.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
The above is the detailed content of How to Redesign & Customize the Django Admin with Bootstrap. For more information, please follow other related articles on the PHP Chinese website!