Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django - Show BooleanField in a formset as one group of radio buttons

I have the following models:

class Profile(models.Model):
    verified = models.BooleanField(default=False)

    def primary_phone(self):
        return self.phone_set.get(primary=True)

class Phone(models.Model):
    profile = models.ForeignKey(Profile)
    type = models.CharField(choices=PHONE_TYPES, max_length=16)
    number = models.CharField(max_length=32)
    primary = models.BooleanField(default=False)

    def save(self, force_insert=False, force_update=False, using=None):
        if self.primary:
            # clear the primary attribute of other phones of the related profile
            self.profile.phone_set.update(primary=False)
        self.save(force_insert, force_update, using)

I'm using Phone in a ModelForm as a formset. What I'm trying to do is to show Phone.primary as a radio button beside each instance of Phone. If I make primary as a RadioSelect widget:

class PhoneForm(ModelForm):
    primary = forms.BooleanField(widget=forms.RadioSelect( choices=((0, 'False'), (1, 'True')) ))

    class Meta:
        from accounts.models import Phone
        model = Phone
        fields = ('primary', 'type', 'number', )

It will show two radio buttons, and they will be grouped together next to each instance. Instead, I'm looking for a way to show only one radio button next to each instance (which should set primary=True for that instance), and have all the set of radio buttons grouped together so that only one of them can be chosen.

I'm also looking for a clean way of doing this, I can do most of the above manually - in my head - but I'm interested to see if there is a better way to do it, a django-style way.

Anyone got an idea?

like image 559
Aziz Alfoudari Avatar asked Mar 18 '12 14:03

Aziz Alfoudari


1 Answers

Ok you've got two dilemma's here. First is you need to group all radio selects from different formsets by giving them the same HTML name attribute. I did that with the add_prefix override below.

Then you have to make sure that the 'primary' field in your post data returns something meaningful, from which you can determine which phone was selected (there should only be one 'name' value in POST data b/c you can only select one radio button from within a group). By assigning the proper prefix value (this needs to be done under _init_ so you can access the self instance), you'll be able to associate the 'primary' value with the rest of its form data (through a custom save method).

I tested a formset with the following and it spat out the right html. So give this a try:

class PhoneForm(ModelForm):
    def __init__ (self, *args, **kwargs)
        super(PerstransForm, self).__init__(*args, **kwargs)
        self.fields['primary'] = forms.BooleanField( widget = forms.RadioSelect(choices=((self.prefix, 'This is my Primary Phone'),))

    #enter your fields except primary as you had before.
    def add_prefix(self, field):
        if field == 'primary': return field
        else: return self.prefix and ('%s-%s' % (self.prefix, field)) or field
like image 50
Eric H. Avatar answered Oct 30 '22 18:10

Eric H.