Skip to content

Instantly share code, notes, and snippets.

@bebosudo
Last active January 25, 2024 02:48
Show Gist options
  • Save bebosudo/d05045f7c80ab48abac02cd882236676 to your computer and use it in GitHub Desktop.
Save bebosudo/d05045f7c80ab48abac02cd882236676 to your computer and use it in GitHub Desktop.
Custom django form widget with no pain.

First of all, edit your_app_settings/settings.py and add:

INSTALLED_APPS = [
    'django.forms',  # to let django discover the built-in widgets
    ...
]

FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'

TEMPLATES = [
    {
        # /stable/topics/templates/#django.template.backends.jinja2.Jinja2
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': [
            'your_app/widgets',
            django.__path__[0] + '/forms/jinja2',
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'environment': 'your_app_settings.jinja2.environment',
            'context_processors': [
                'django.template.context_processors.debug',
            ],
        },
    },
    ...
]

Then create a directory your_app/widgets/your_app and place the files you want to use inside it, for example bulma_select.html:

<div class="select">{% include "django/forms/widgets/select.html" %}</div>

This widget simply adds a div with a select class around the select widget, so that bulma (https://bulma.io) renders select dropdowns with the correct styling; it then delegates the normal select rendering to the jinja2 select.html widget template.

Eventually, in your_app/forms.py you can create a specific widget class:

class BulmaCSSSelectWidget(forms.widgets.Select):
    template_name = "your_app/bulma_select.html"

or, if you want to edit a widget "on the fly" e.g., inside __init__, you can use:

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields:
            widget = self.fields[field].widget

            # No idea why the Textarea widget doesn't implement .input_type:
            # /en/stable/_modules/django/forms/widgets/#Textarea
            if isinstance(widget, forms.widgets.Textarea):
                widget.attrs.update({"class": "textarea"})
            elif widget.input_type in ("text", "password", "date", "number"):
                widget.attrs.update({"class": "input"})
            elif widget.input_type == "select":
                widget.template_name = "your_app/bulma_select.html"         # this
            ...

By wrapping this __init__ into a class, it can be applied to all forms/modelforms, using inheritance, without touching the single fields widget.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment