# django-colorfield and the admin colour picker you would otherwise write

> django-colorfield is a small Django model field that stores a colour and renders a picker widget in the admin, with hex, hexa, rgb and rgba formats, an option to derive the colour from an image, and a palette that can be advisory or restrictive. It fits a Django project that needs a colour on a model, and it does nothing beyond the admin.

**fabiocaccamo/django-colorfield** — :art: color field for django models with a nice color-picker in the admin.

- Repository: https://github.com/fabiocaccamo/django-colorfield
- Stars: 660 · Forks: 94
- Language: Python
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/fabiocaccamo-django-colorfield

## Four storage formats and one widget, and the field is the whole package

django-colorfield is described simply as a color field for your models with a nice color-picker in the admin, and the implementation matches that description closely.

A model field is added the way you would expect:

```python
from colorfield.fields import ColorField
from django.db import models

class MyModel(models.Model):
    color = ColorField(default='#FF0000')
```

The supported storage formats are `hex`, which is the default, `hexa`, `rgb` and `rgba`. The format is a field option, so the choice of representation is per field rather than per project:

```python
from colorfield.fields import ColorField
from django.db import models

class MyModel(models.Model):
    color = ColorField(format="hexa")
```

The admin then provides a simple color picker for all color fields, and the readme notes the picker comes from the coloris project at coloris.js.org. The widget is a JavaScript picker rather than a native browser input, which is the whole reason the package needs a static files step.

Two details about the scope are worth stating because they are easy to miss. The package doesn't need any setting, which is unusual for a Django app that ships static assets and a widget, and the field lives in two places. `colorfield.fields.ColorField` is the model field, and `colorfield.forms.ColorField` is the form field for use outside a model context, so you get a picker in a plain form as well as in a ModelForm.

The project was originally developed by Jared Forsyth, who is listed first among the authors in the package metadata alongside Fabio Caccamo, who is the maintainer.

## samples is a suggestion and choices is a rule, and the difference matters

The palette option is where the interesting design decision sits, and the documentation is explicit about the distinction.

It is possible to provide a palette of colors to choose from to the widget using the `samples` option, and this option is not restrictive, on the contrary of the `choices` option, and it is also possible to choose another color from the spectrum.

```python
from colorfield.fields import ColorField
from django.db import models

class MyModel(models.Model):

    COLOR_PALETTE = [
        ("#FFFFFF", "white", ),
        ("#000000", "black", ),
    ]

    # not restrictive, allows the selection of another color from the spectrum.
    color = ColorField(samples=COLOR_PALETTE)

    # restrictive, it is mandatory to choose a color from the palette
    color = ColorField(choices=COLOR_PALETTE)
```

So the same tuple list can be used two ways. With `samples`, the palette appears as swatches in the picker and the user can still pick any other colour. With `choices`, the palette is the complete set of permitted values.

That difference is a genuine design choice rather than a naming quirk, because the two options put the constraint in different places. `samples` is a UI affordance, and the value that lands in the database is whatever the user picked. `choices` is a data constraint, and Django's own validation is what enforces it, so a value that arrives through a form, an API or a data migration still has to satisfy the list.

For a project with a brand palette, `samples` is usually what you want, because it guides the eye without getting in the way. For a project where only a fixed set of colours is legitimate, `choices` is the one, and the tuple form with the label is what makes the admin display readable.

## image_field takes the top-left pixel, every save

The `image_field` option is the one with a behaviour that surprises people, and it is documented in a single sentence.

It is possible to auto-populate the field value getting the color from an image using the `image_field` option, and the color will be calculated from the top-left pixel color of the image each time the model instance is saved.

```python
from colorfield.fields import ColorField
from django.db import models

class MyModel(models.Model):
    image = models.ImageField(upload_to="images")
    color = ColorField(image_field="image")
```

The design is straightforward: an ImageField and a ColorField, with the color derived from the image rather than typed. The implementation consequence is the part to think about. The value is recalculated on every save, so it is derived state that lives in the database. If someone edits the colour by hand in the admin and saves, the image is still there, so the next save overwrites the manual edit with the pixel value again. The colour is effectively read-only once an image is attached, whether or not the widget says so.

There is a second consequence in the phrase top-left pixel. That is a coordinate, not an average, not a dominant colour, not anything perceptual. It works for images that are a flat swatch, which is the obvious use case, and for a cover image whose top-left corner happens to be a brand colour. For an image that is a photo, the value is the colour of one pixel in one corner, which is a defensible technical choice for a derived field and a strange one for a design system.

The `image_field` option also explains the package's single runtime dependency, Pillow at 9.0.0 or newer, since reading a pixel means decoding the image.

## Forms work in both model and plain contexts

The form API is the reason this package is more than an admin convenience, because the widget is available wherever a form is.

The `colorfield.fields.ColorField` can be used in Django model forms, `django.forms.ModelForm`, to provide a color picker widget, and when used in a model form the field automatically validates the color format based on the specified `format`, for example `hex`, `rgb` or `rgba`.

```python
from django import forms

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        fields = ["color"]
```

For plain forms, `django.forms.Form`, the documentation is direct about when it is useful: this is useful when you need a color input outside of a model context.

```python
from django import forms
from colorfield.forms import ColorField

class MyForm(forms.Form):
    color = ColorField(initial="#FF0000", format="hex")
```

The format-driven validation is the part worth noting. Because the field knows which format it is storing, it can reject a malformed value, and that validation applies in the plain form case too, where there is no model to fall back on. So the same field type enforces the same rule whether the colour comes from a model admin, a ModelForm, a plain form or an API serializer built on top of the model field.

The practical upshot is that the format is a schema decision, not a display decision. Changing it later is a data migration, not a settings change, because the values already in the database were written in the old representation.

## Installation is four steps and a static files run

The install is short enough to state in full.

-   Run `pip install django-colorfield`
-   Add `colorfield` to `settings.INSTALLED_APPS`
-   Run `python manage.py collectstatic`
-   Restart your application server

The `collectstatic` step is not optional, and that is the one operational thing to remember. The picker is a JavaScript widget, so its assets have to be gathered by the same static files pipeline as the rest of your admin, and a deployment that skips it gets a field that renders as a plain text input with no visible error.

The dependency set is small. The package metadata lists a single runtime dependency, Pillow at 9.0.0 or newer, and the requirements file asks for Django 4.2 or newer alongside the same Pillow floor. The package requires Python 3.11 or newer, and the classifiers cover Python 3.11 through 3.14 and Django 4.1 through 6.1, with a development status of Production/Stable.

For development on the package itself, the readme gives the full sequence: clone the repository, create a virtualenv and activate it, upgrade pip, install the requirements with `pip install -r requirements.txt -r requirements-test.txt`, install pre-commit with `pre-commit install --install-hooks` to run the formatters and linters, and then run the tests with tox, or `python runtests.py`, or `python -m django test --settings "tests.settings"`.

The repository layout supports that workflow: a `tests/` directory with a settings module, `runtests.py`, `tox.ini`, separate `requirements.txt` and `requirements-test.txt`, a pre-commit config, and the `colorfield/` package itself.

## What this package does not do, and the alternative to consider

There are three limits, and they are all about scope rather than bugs.

The first is that everything here happens in the admin and in forms. There is no widget for a public facing page, no JavaScript API for a colour picker in your own templates, and no mention of a front end component library. If a customer picks a colour on your own site rather than an administrator, this package does not help you.

The second is that the value is stored as text. A colour in `hex`, `hexa`, `rgb` or `rgba` is a string in a character column, and the package does not provide a database type, a normalisation, or a way to query by colour. A project that wants to find the nearest colour to a given one, or index colours for a filter, is doing that itself.

The third is the derived value problem, which comes back to the `image_field` option. If a colour is computed from an image on every save, it is a cache of a calculation, and it behaves like one: it drifts if the image is replaced by other means, and it cannot be corrected by hand.

The alternative to weigh is not another Django package, it is doing it in two lines of your own code. A `CharField` with a `TextInput` widget and a small JavaScript picker attached gives you the same admin experience for a fixed set of colours, and the field itself is then plain Django, with no collectstatic step, no Pillow dependency and no format to migrate later. The case for the package is the widget, the format validation and the image derived option, all of which you would otherwise write and maintain yourself.

The judgement for most projects is that a colour field is a small enough problem that the deciding factor is the admin experience rather than the storage, and if you want a picker the package gives you a good one for very little code. If you want a fixed brand palette, the `choices` option turns the field into ordinary Django validation and the widget becomes a convenience rather than a dependency you depend on.

## Conclusion

django-colorfield fits a Django project whose models carry a colour that an editor picks in the admin, where the alternative is a plain CharField and a free text box, and where the colour must come back out of the database in a usable form. It is the wrong tool if you need the colour to be a computed or constrained value rather than a chosen one, since the samples option is advisory and the image option takes the top-left pixel. Before you add it, verify two things: that your Django version is covered, with the classifiers running from 4.1 to 6.1 and the requirements asking for Django 4.2 or newer, and that the `image_field` option reads the pixel you expect, because the documentation says the colour is calculated from the top-left pixel of the image each time the model instance is saved. The code is MIT licensed, the last push was on 2026-10-13, and the newest release is 0.14.0 from 2025-04-30.

## FAQ

### What does django-colorfield do?

It adds a colour field to Django models and provides a colour picker widget in the admin for all colour fields. The field stores the value as text in one of four supported formats and validates the format automatically when used in a form.

### How do I install django-colorfield?

Run `pip install django-colorfield`, add `colorfield` to `settings.INSTALLED_APPS`, run `python manage.py collectstatic` so the picker assets are gathered, and restart your application server. The package needs Pillow 9.0.0 or newer, Django 4.2 or newer and Python 3.11 or newer.

### What is the difference between samples and choices in django-colorfield?

Both take a palette of tuples, but `samples` is not restrictive and the user can still choose another colour from the spectrum, while `choices` is restrictive and it is mandatory to choose a colour from the palette. The documentation states the samples option is not restrictive, on the contrary of the choices option.

### How does the image_field option work in django-colorfield?

It auto-populates the field value from an image, and the colour is calculated from the top-left pixel colour of the image each time the model instance is saved. The example pairs it with a `models.ImageField` and passes the field name via `ColorField(image_field="image")`.

### Can I use a colour picker outside the Django admin?

Yes. The `colorfield.forms.ColorField` can be used in plain Django forms, `django.forms.Form`, when you need a colour input outside a model context, for example `color = ColorField(initial="#FF0000", format="hex")`. The format-driven validation applies there too.

## Sources

- [fabiocaccamo/django-colorfield on GitHub](https://github.com/fabiocaccamo/django-colorfield)
- [Issues](https://github.com/fabiocaccamo/django-colorfield/issues)
- [License: MIT](https://github.com/fabiocaccamo/django-colorfield/blob/main/LICENSE)
- [README](https://github.com/fabiocaccamo/django-colorfield/blob/main/README.md)
- [Releases](https://github.com/fabiocaccamo/django-colorfield/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/fabiocaccamo-django-colorfield
