Login

Allow disabling options in a select widget

Author:
scjody
Posted:
June 3, 2011
Language:
Python
Version:
1.3
Score:
4 (after 4 ratings)

HTML allows an option in a <select> to be disabled. In other words it will appear in the list of choices but won't be selectable. This is done by adding a 'disabled' attribute to the <option> tag, for example: <option value="" disabled="disabled">Disabled option</option> This code subclasses the regular Django Select widget, overriding the render_option method to allow disabling options. Example of usage: class FruitForm(forms.Form): choices = (('apples', 'Apples'), ('oranges', 'Oranges'), ('bananas', {'label': 'Bananas', 'disabled': True}), # Yes, we have no bananas ('grobblefruit', 'Grobblefruit')) fruit = forms.ChoiceField(choices=choices, widget=SelectWithDisabled()) </option></select>

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from django.forms.widgets import Select
from django.utils.encoding import force_unicode
from django.utils.html import escape, conditional_escape


class SelectWithDisabled(Select):
    """
    Subclass of Django's select widget that allows disabling options.
    To disable an option, pass a dict instead of a string for its label,
    of the form: {'label': 'option label', 'disabled': True}
    """
    def render_option(self, selected_choices, option_value, option_label):
        option_value = force_unicode(option_value)
        if (option_value in selected_choices):
            selected_html = u' selected="selected"'
        else:
            selected_html = ''
        disabled_html = ''
        if isinstance(option_label, dict):
            if dict.get(option_label, 'disabled'):
                disabled_html = u' disabled="disabled"'
            option_label = option_label['label']
        return u'<option value="%s"%s%s>%s</option>' % (
            escape(option_value), selected_html, disabled_html,
            conditional_escape(force_unicode(option_label)))

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

davea (on May 24, 2017):

Django 1.11 introduced a different way of rendering widgets; I've updated this snippet to work as expected in 1.11:

class SelectWithDisabled(Select):
    """
    Subclass of Django's select widget that allows disabling options.
    To disable an option, pass a dict instead of a string for its label,
    of the form: {'label': 'option label', 'disabled': True}
    """

    def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
        disabled = False
        if isinstance(label, dict):
            label, disabled = label['label'], label['disabled']
        option_dict = super(SelectWithDisabled, self).create_option(name, value, label, selected, index, subindex=subindex, attrs=attrs)
        if disabled:
            option_dict['attrs']['disabled'] = 'disabled'
        return option_dict

#

clarsen (on September 19, 2024):

With django 5.x, ChoiceWidget (parent class of Select) widget performs normalize_choices on initializing choices:

@choices.setter
def choices(self, value):
    self._choices = normalize_choices(value)

which results in dictionary being converted into list. Passing choices as

[('a', 'a'), (None, 'this is a label'), (None, {'label': 'this is a disabled label', 'disabled': True})]

results in ChoiceWidget.choices as

[('a', 'a'), (None, 'this is a label'), (None, [('label', 'this is a disabled label'), ('disabled', True)])]

which causes rendering to fail.

As a workaround, override the setter/getter as:

@forms.Select.choices.setter
def choices(self, value):
    self._choices = value

#

Please login first before commenting.