Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a Django form with a RadioSelect field, and some buttons disabled?

I'm creating a Django form with a set of Radio buttons (as a single RadioSelect field), and I'd like to have some of the buttons grayed out. However, given that the RadioSelect field is a single field on the form, I haven't found a way to do that.

class OrderStatusForm(forms.Form):
    os = Order_Status.objects.values_list('id', 'status')
    status = forms.ChoiceField(choices=os, widget=forms.RadioSelect())

def makeForm():
    newForm = OrderStatusForm()
    # next line disables all radio buttons.
    newForm.fields['status'].widget.attrs['disabled'] = True

Is there some way to selectively disable the individual radio buttons? Or do I just have to not put the disabled options in the list in the first place?

like image 765
John C Avatar asked Aug 12 '11 23:08

John C


1 Answers

Further research turned up the fact that the RadioSelect renderer can be replaced, and passed in as a parameter to the initial widget creation function. So I created my own renderer, and attached a list of Booleans, indicating which Radio buttons should be disabled.

The renderer adds a disabled attribute to each Radio button widget as needed, then the force_unicode turns the widget's attributes into HTML that include a disabled="True" value.

from django.utils.safestring import mark_safe
from django.utils.encoding import force_unicode

class RandomRenderer(forms.RadioSelect.renderer):
    """ Modifies some of the Radio buttons to be disabled in HTML,
    based on an externally-appended Actives list. """
    def render(self):
        if not hasattr(self, "actives"): # oops, forgot to add an Actives list
            return self.original_render()
        return self.my_render()

    def original_render(self):
        return mark_safe(u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>'
            % force_unicode(w) for w in self]))

    def my_render(self):
        midList = []
        for x, wid in enumerate(self):
            if self.actives[x] == False:
                wid.attrs['disabled'] = True
            midList.append(u'<li>%s</li>' % force_unicode(wid))
        finalList = mark_safe(u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>'
            % w for w in midList]))
        return finalList

class OrderStatusForm(forms.Form):
    os = Order_Status.objects.values_list('id', 'status', 'reason')
    activeList = [True, False, True, False, True, False,]
    newStatus = forms.ChoiceField(widget=forms.RadioSelect(
        renderer=RandomRenderer), choices=os)
    newStatus.widget.renderer.actives = activeList

It's a little kludgy - I'm just sticking the actives list directly onto the renderer, which works (love Python's duck-typing), but would be cleaner if I passed the list in some constructors. Unfortunately I had problems with that, so took the easy way out. :)

like image 104
John C Avatar answered Nov 15 '22 08:11

John C