Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

From the View, how do I pass custom "choices" into a form's ChoiceField?

According to Django docs., the ChoiceField accepts an iterable of two tuples, "or a callable that returns such an iterable" to use as choices for the field.

I've defined ChoiceFields within my forms:

class PairRequestForm(forms.Form):
    favorite_choices = forms.ChoiceField(choices=[], widget=RadioSelect, required=False)

Here is the view where I'm attempting to pass a tuple of custom choices:

class PairRequestView(FormView):
    form_class = PairRequestForm

    def get_initial(self):
        requester_obj = Profile.objects.get(user__username=self.request.user)
        accepter_obj = Profile.objects.get(user__username=self.kwargs.get("username"))

        # `get_favorites()` is the object's method which returns a tuple.
        favorites_set = requester_obj.get_favorites()

        initial = super(PairRequestView, self).get_initial()

        initial['favorite_choices'] = favorites_set

        return initial

Within my models.py, here is the method used above that returns a tuple:

def get_favorites(self):
        return (('a', self.fave1), ('b', self.fave2), ('c', self.fave3))

From my understanding, if I want to pre-populate the form, I pass data in by overriding get_initial(). I attempt to set the initial data of the form's favorite_choices with a callable. The callable being favorites_set.

With the current code, I am given an error of 'tuple' object is not callable

How can I pre-populate the RadioSelect ChoiceField with my own choices?

edit: I've also tried setting initial['favorite_choices'].choices = favorites_set

like image 568
Jay Jung Avatar asked Nov 18 '17 06:11

Jay Jung


3 Answers

The get_initial method is made to populate the initial value of the fields of your form. Not to set the available choices or to modify your fields attributes.

To successfully passing your choices from your view to the form, you need to implement the get_form_kwargs method in your view:

class PairRequestView(FormView):
    form_class = PairRequestForm

    def get_form_kwargs(self):
        """Passing the `choices` from your view to the form __init__ method"""

        kwargs = super().get_form_kwargs()

        # Here you can pass additional kwargs arguments to the form.
        kwargs['favorite_choices'] = [('choice_value', 'choice_label')]

        return kwargs

And in your form, get the choices from the kwargs argument in the __init__ method and set the choices on the field:

class PairRequestForm(forms.Form):

    favorite_choices = forms.ChoiceField(choices=[], widget=RadioSelect, required=False)

    def __init__(self, *args, **kwargs):
        """Populating the choices of  the favorite_choices field using the favorites_choices kwargs"""

        favorites_choices = kwargs.pop('favorite_choices')

        super().__init__(*args, **kwargs)

        self.fields['favorite_choices'].choices = favorites_choices

And voilà !

like image 195
Clément Denoix Avatar answered Nov 03 '22 18:11

Clément Denoix


Another simple way of doing this would be:

class PairRequestView(FormView):
    form_class = PairRequestForm

    def get_form(self, *args, **kwargs):
         requester_obj = Profile.objects.get(user__username=self.request.user)
         favorites_set = requester_obj.get_favorites()
         form = super().get_form(*args, **kwargs)
         form.fields['favorite_choices'].choices = favorites_set
         return form
like image 45
javed Avatar answered Nov 03 '22 19:11

javed


You should encapsulate the choices in a proper parameter to the contructor of the form. Say you have a drop-down for 'groups' and you want to pass 'group choices':

class CreateAccountForm(forms.Form):

   def __init__(self, groupChoices_, *args, **kwargs):
      super(CreateAccountForm, self).__init__(*args, **kwargs)
      self.fields['group'].choices = groupChoices_

   group = forms.ChoiceField()

In your view, use groupChoices_ always as the 1st argument, e.g:

groupChoices = [
  (2, 'A'),
  (4, 'B'),
]
form = CreateAccountForm(groupChoices, request_.POST)

No need to worry about kwargs horribleness!

like image 25
Elendurwen Avatar answered Nov 03 '22 20:11

Elendurwen