How to override css in Django Admin?
Asked Answered
M

9

116

I want to change certain css in admin django like base.css. Is it better to change directly in the django library? How can I override it in the best way?

Metatarsal answered 9/9, 2011 at 4:6 Comment(0)
U
134

It depends a lot of what you want to do. Though first of all: do not overwrite it in the Django admin directly. You got two options I think are reasonable:

  1. If you want to change the appearance of the admin in general you should override admin templates. This is covered in details here: Overriding admin templates. Sometimes you can just extend the original admin file and then overwrite a block like {% block extrastyle %}{% endblock %} in django/contrib/admin/templates/admin/base.html as an example.
  2. If your style is model specific you can add additional styles via the Media meta class in your admin.py. See an example here:
class MyModelAdmin(admin.ModelAdmin):
    class Media:
        js = ('js/admin/my_own_admin.js',)    
        css = {
             'all': ('css/admin/my_own_admin.css',)
        }
Unhorse answered 9/9, 2011 at 4:38 Comment(7)
Actually, it's not model level but the whole site itself. To be specific changes in base.css,ie.css etc. One option is to include the admin/base.html in my application itself and use my custom base.css in the admin/base.html file. That way I will have to include some template files from the django admin to my own site. Is there any better solution than this ?Metatarsal
None I am aware of. The django admin is in the end nothing else than a django reusable app. That's the way to go with any other reusable app as well.Unhorse
I notice there's a .css file listed within the js here... does that actually work? I can't get it to.Withdraw
Yes, you are right. I made a mistake and edited my answer with an example from the django docs.Unhorse
In the words of Eli Porter, "You grilled the best cat".Harriette
@Gabriel I can not answer you that. Wagtail wasn't around when I wrote this answer and I haven't used it yet. The django admin uses some special handling here, which Wagtail might not implement the same way.Unhorse
@TorstenEngelbrecht Yesss, i am use with Wagtail and is work!Catmint
B
59
  • In settings.py, make sure your app is listed before admin in the INSTALLED_APPS.
  • Create (your-app)/templates/admin/base_site.html and put the <style> block into the {% block extrahead %}

Example:

{% extends "admin/base_site.html" %}
{% block extrahead %}
    <style>
        .field-__str__ {
            font-family: Consolas, monospace;
        }
    </style>
{% endblock %}
Brume answered 30/1, 2018 at 16:25 Comment(3)
Best answer. If you want you can also avoid to list your app before admin in INSTALLED_APPS by putting a "template" directory in base project and referencing it in settings.py: TEMPLATES = [ ...other stuffs..., 'DIRS': [os.path.join(BASE_DIR, 'templates')], ]Och
Great idea! Works smoothly like a charm!Weakwilled
If you use a custom authentication user model and want to unregister the authentication group model in admin.py, make sure to list django.contrib.auth before your app.Schism
S
36

This solution will work for the admin site, I think it's the cleanest way because it overrides base_site.html which doesn't change when upgrading django.

Create in your templates directory a folder called admin in it create a file named base_site.html.

Create in your static directory under css a file called admin-extra.css .

Write in it all the custom css you want for your forms like: body{background: #000;}.

Paste this in the base_site.html:

{% extends "admin/base.html" %}
{% load static from staticfiles %} # This might be just {% load static %} in your ENV

{% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}

{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "css/admin-extra.css" %}" />{% endblock %}

{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></h1>
{% endblock %}

{% block nav-global %}{% endblock %}

As mentioned in the comments: make sure your app is before the admin app in INSTALLED_APPS, otherwise your template doesn't override django's

That's It! you're done

Supraliminal answered 19/5, 2016 at 8:8 Comment(7)
Thanks, works great! If it doesn't work, make sure your app is before the admin app in INSTALLED_APPS, otherwise your template doesn't override django's.Grandfather
Best answer and comment. It is surprisingly difficult to change the coloring on the admin page. Going through this answer and comment did solidify how it works.Decemvir
How do you know that base_site.html will never change when upgrading django? (I mean yes this answer is 3 years old and still works but that's no garantuee)Vociferance
@marv if you look under the hood in the source code you can see very easily the admin architecture is built around these specific names especially in the urls and the template rendering. classes that inherit classes that inherit classes rely on these names staying the same unless there will be a major redesign of the Django framework (and even then I wouldn't bet on this changing) the overall basic convention of overriding admin views and admin urls as well as overriding the base template will stay the same for the next 3 years at the least according to django roadmap.Supraliminal
So this is just general knowledge about django and there is no concrete source confirming this? It's not that i doubt you, I just wonder how one is supposed to find out that this is the case.Vociferance
I love knowledge and doubts (hence the +1 for your comments). there is an official road map for each django version as well as issues and tickets which are "good to have". I haven't found any mentions of this being changed/revisited or even complaints regarding the admin url/view/templating naming convention. Everything is open source and you can look it up for yourself.Supraliminal
some times all you need is to clear your browser cacheFirry
P
29

I just extended admin/base.html to include a reference to my own css file - at the end. The beauty of css is that you don't have to touch existing definitions, just re-define.

Prepay answered 9/9, 2011 at 5:33 Comment(0)
E
19

In your static directory, create a static/admin/css/base.css file.

Paste in Django's default Admin CSS first, then add your customizations at the bottom.

Enounce answered 6/9, 2013 at 2:26 Comment(4)
If you do this, be sure to put your app BEFORE django.contrib.admin in the list of INSTALLED_APPS. If you don't, collectstatic will find the admin base.css first and your customized version won't overwrite it.Goutweed
This isn't a good long term solution. It copy/pastes a bunch of code and it won't be maintained as Django upgrades.Morales
Any styling to the Django admin is basically a fork of the code. An update to Django could in effect break your customizations. My recommendation is to keep customizations to a minimum and add them at the bottom of Django's default styling. Then you can manually update the default styling if and when you want to.Enounce
@danny-w-adair's answer above is better; keeps things "DRY", but it's still a fork of Django's code that could lead to minor upgrade pains.Enounce
M
14

If you want a global scope and you don't want to think about overriding templates a mixin works really well for this. Put this code wherever you want:

class CSSAdminMixin(object):
    class Media:
        css = {
            'all': ('css/admin.css',),
        }

Then, make a CSS file called admin.css with your overrides, for example:

select[multiple] {
    resize: vertical;
}

Then, in whatever models you want, do:

class MyModelAdmin(admin.ModelAdmin, CSSAdminMixin):

And you'll be all set.

Morales answered 26/7, 2017 at 16:51 Comment(2)
I like your answer, but why not to add directly to MyModelAdminProtohuman
You could do that if it's one model, but it'll get messy if you do it to many models.Morales
R
5

Have admin/css/changelists.css inside a folder in STATICFILES_DIRS, and it will user that changelists.css instead of the default admin one.

Rotherham answered 12/5, 2015 at 12:53 Comment(0)
P
2

You can override base.css in Django Admin.

For example, there is Person model as shown below:

# "app1/models.py"

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=20)

    def __str__(self):
        return self.name

Then, there is Person admin as shown below:

# "app1/admin.py"

from django.contrib import admin
from .models import Person

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    pass

Then, there is Person admin as shown below:

enter image description here

Then, copy base.css from django/contrib/admin/static/admin/css/base.css in your virtual environment to static/admin/app1/css/ as shown below:

django-project
 |-core
 |  └-settings.py
 |-app1
 |  |-models.py
 |  └-admin.py
 |-app2
 └-static
    └-admin
       └-app1
          └-css
             └-base.css # Here

Then in base.css, replace background: var(--header-bg); with background: black; as shown below to change the header color to black in Person admin page:

/* "static/admin/app1/css/base.css" */

#header {
    width: auto;
    height: auto;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px 40px;
    /* background: var(--header-bg); */
    background: black;
    color: var(--header-color);
    overflow: hidden;
}

First, I explain how to change the header color to black in Person admin page.

So, set "admin/app1/css/base.css" to css in Media class as shown below:

# "app1/admin.py"

from django.contrib import admin
from .models import Person

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    class Media:
        css = {    # ↓ ↓ ↓ ↓ ↓ ↓ Here ↓ ↓ ↓ ↓ ↓ ↓
            "all": ("admin/app1/css/base.css",)
        }      

Then, the header color is changed to black in Person admin page as shown below:

enter image description here

And, the header color is not changed to black in Animal admin as shown below:

enter image description here

Next, I explain how to change the header color to black in all admin pages.

So, copy base.html from /django/contrib/admin/templates/admin/base.html in your virtual environment to /templates/admin/base.html as shown below:

django-project
 |-core
 |  └-settings.py
 |-app1
 |  |-models.py
 |  └-admin.py
 |-app2
 |-static
 |  └-admin
 |     └-app1
 |        └-css
 |           └-base.css # Here
 └-templates
    └-admin
       └-base.html # Here

Then in base.html, replace admin/css/base.css with admin/app1/css/base.css in {% static %}:

# "templates/admin/base.html"

# ...
<title>{% block title %}{% endblock %}</title>
{# <link rel="stylesheet" href="{% block stylesheet %}{% static "admin/css/base.css" %}{% endblock %}"> #}
{# ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ Here ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ #}
<link rel="stylesheet" href="{% static "admin/app1/css/base.css" %}"> {# ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ Here ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ #}
{% block dark-mode-vars %}
#...

Then, the header color is changed to black in Person and Animal admins as shown below:

enter image description here

enter image description here

Priam answered 12/5, 2023 at 12:6 Comment(0)
L
0

It just so happens that using <style> tag inside {% block extrastyle %}{% endblock %} did not work for me when I wanted to override css. Theming support provides the correct way. All I was missing is {{ block.super }} :-

{% extends 'admin/base.html' %}

{% block extrastyle %}{{ block.super }}
<style>
--- your style ---
--- properties here ---
</style>
{% endblock %}
Lahr answered 26/8, 2022 at 10:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.