Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a ChoiceField.choices callable know what choices to return?

Tags:

django-forms

In Django 1.8, the ChoiceField's choices argument can accept a callable:

def get_choices():
    return [(1, "one"), (2, "two")]

class MyForm(forms.Form):
    my_choice_field = forms.ChoiceField(choices=get_choices)

In the above example, get_choices() always returns the same choices. However, being able to assign a callable to choices does not make much sense unless that callable knows something like, say, an object id, each time it is called. How can I pass such a thing to it?

like image 984
Antonis Christofides Avatar asked Jun 09 '15 11:06

Antonis Christofides


People also ask

How do you define choice fields in Django?

Django Field Choices. According to documentation Field Choices are a sequence consisting itself of iterables of exactly two items (e.g. [(A, B), (A, B) …]) to use as choices for some field. For example, consider a field semester which can have options as { 1, 2, 3, 4, 5, 6 } only.

How to use choice Field in Django forms?

ChoiceField in Django Forms is a string field, for selecting a particular choice out of a list of available choices. It is used to implement State, Countries etc. like fields for which information is already defined and user has to choose one. It is used for taking text inputs from the user.


1 Answers

You can't do it in the form declaration because the CallableChoiceIterator calls the function without arguments that he gets from here. Doing in the __init__ Form method is easier than creating your own ChoiceField I guess. Here is what I suggest:

class MyForm(forms.Form):
    my_choice_field = forms.ChoiceField(choices=())

    def __init__(self, *args, **kwargs):
        # Let's pass the object id as a form kwarg
        self.object_id = kwargs.pop('object_id') 

        # django metaclass magic to construct fields
        super().__init__(*args, **kwargs)

        # Now you can get your choices based on that object id            
        self.fields['my_choice_field'].choices = your_get_choices_function(self.object_id)

That supposes that you have some Class Based View that looks that has a method like this :

class MyFormView(FormView):
   # ...

   def get_form_kwargs(self):
       kwargs = super().get_form_kwargs()
       kwargs['object_id'] = 'YOUR_OBJECT_ID_HERE'
       return kwargs

   # ...

P.S : The super() function call supposes you are using python 3

like image 51
Anas Avatar answered Sep 17 '22 01:09

Anas