Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Override ChoiceField widget in Django ModelForm without re-specifying choices

I am trying to override the default widget for a Django ChoiceField while preserving the choices generated in the model. Here is the relevant part of my model:

class UserGroup(models.Model):
    icon = models.CharField(max_length=100, choices=<function call>)

And of my form:

class UserGroupForm(forms.ModelForm):
    icon = models.ChoiceField(widget=IconPicker)

    class Meta:
        model = UserGroup
        fields = [ 'icon', ]

Overriding the ChoiceField's widget like this clobbers the form.fields['icon'].choices attribute normally inherited from the model and sets it to [] because Django. If I remove the icon field definition from the form, the choices are preserved - but of course the widget defaults to a Select.

(The function which generates the choices for the model field is not accessible from the form code unfortunately.)

The best I have come up with so far for is to change the icon form field definition to

icon = ChoiceField(choices=UserGroup._meta.get_field_by_name('icon')[0].choices, 
                   widget=IconPicker)

but this is clunky and I would rather have the choices automatically passed on as in the introspected ChoiceField behavior. (I tried subclassing ChoiceField to IconChoiceField which was identical but for a default widget of IconPicker but Django converts it back to a TypedChoiceField with the default Select widget because of this issue.)

Is there a way to override the ChoiceField's widget attribute while preserving the behavior of inheriting choices from the model?

like image 976
Eric P Avatar asked Dec 15 '22 22:12

Eric P


1 Answers

I think the reason you are losing the choices you specified in your model i.e. "sets it to []" is not "because Django", but because you override the icon field with the line icon = models.ChoiceField(widget=IconPicker)

Please note that if you are using a modelform then it is not necessary to override the widget at init, instead the widget should be specified in the Meta class in the widgets dictionary.

class UserGroupForm(forms.ModelForm):

    class Meta:
        model = UserGroup
        fields = [ 'icon', ]
        widgets = {
            'icon': IconPicker
        }

As for overriding the choices you can simply do self.fields['icon'].choices = UserGroupForm.ICON_CHOICES, but I don't think you need to override choices in this instance.

like image 135
Tom Avatar answered May 12 '23 03:05

Tom