When I add a new model to the Django app at work, I try to make sure the results in the Django admin have good usability, too. Just because it'll be mainly developers (and a few project managers) seeing it doesn't mean I can neglect usability. Consequently, I spend some time on hacking the Django admin. My manager says I've been making it do things he didn't even realize were possible.
The most recent thing I did was add a color field to a model. I considered Django Colorfield, but there's an open issue about it using GPLv3-licensed code while being MIT-licensed. 😬 So, I dug around a bit.
Basic color picker
First, I set up the model to have a primary_color
that's a CharField
of length 7, to accommodate a standard"#FF00FF"
RGB HEX code.
class MyModel(models.Model):
primary_color = models.CharField(max_length=7, default="#FFFFFF")
Then, I found a StackOverflow answer that pointed out that the Django docs include how to override the widget used for a form element, so you can change which HTML5 rendering is used for <input>
fields. Cool! So I just needed to add a forms.py
like this:
from django.forms import ModelForm
from django.forms.widgets import TextInput
from myapp.models import MyModel
class MyModelForm(ModelForm):
class Meta:
model = MyModel
fields = "__all__"
widgets = {
"primary_color": TextInput(attrs={"type": "color"}),
}
and update the admin.py
to use it:
from myapp.forms import MyModelForm
@admin.register(MyModel)
class MyModel(admin.ModelAdmin):
form = MyModelForm
and I'd be all set, right? Indeed, it did now show me a filled-in color block in the admin!
Adding a tooltip
But I still wasn't happy. I wanted a way to see the HEX code for the color just by looking at it in the admin. With the HTML5 element's behavior, you have to click on the color block to get a pop-up color picker and go from there to find the HEX. In Chrome on my Mac, I had to click two more times to get it to HEX mode. Ugh.
So, I dug around some more. I wasn't able to find a way to display the HEX alongside the color block, so I decided to try for putting it in a tooltip. I needed a way to get the instance of the form field, so I could read its value. With further searching, I stumbled upon a mostly-unrelated StackOverflow answer that mentioned self.instance
. Great, now I just had to figure out where self
was accessible from in ModelForm
. Almost there! After consulting the Django docs to see which methods have access to self
, I landed on this solution. In that same MyModelForm
class in forms.py
, I added:
def __init__(self, *args, **kwargs):
super(MyModelForm, self).__init__(*args, **kwargs)
if self.instance:
self.fields["primary_color"].widget = TextInput(
attrs={"type": "color", "title": self.instance.primary_color}
)
This grabs the value of the color field and sets it as the title attribute on the element. Title attributes display as tooltips in the browser.
Top comments (3)
So simple solution! html5 has many advantages but hate to struggle with those details, I always end up doing things with javascript 😅
I’m from the 90s. As far as I’m concerned, Javascript is a last resort!
Yes, like everything "it should". Where I work we must take into account old browsers (including Internet Explorer) and even smartphones from 2007. So javascript ends up being a multiplatform standard.
I thunk, it depends on the project, it depends on what they decide, I don't make those decisions.