Search code examples
djangodjango-admindjango-formsdjango-widget

Django admin - dynamically update through ajax choices of a ChoiceField in ModelForm


I'm working with a ModelForm in the admin. I have two ChoiceFields which are populated with choices in __init__:

self.fields['city'] = forms.ChoiceField(
        required=False,
    )
self.fields['city'].choices=get_cities_tuple(region_code=region_code)
self.fields['city'].initial = my_initial_city_value

self.fields['zip'] = forms.ChoiceField(
        required=False,
    )
self.fields['zip'].choices=get_cities_tuple(region_code=region_code, city_name=city_name)
self.fields['zip'].initial = my_initial_zip_value

now the options of those html select rendered are dynamically updated through ajax functions. The problem is that while saving, the selected options is recognized as not valid cause is not in the initial choices:

Select a valid choice. <my_choice> is not one of the available choices.

Any idea on how to solve it?

Maybe subclassing the original ChoiceField or the Select widget?


Solution

  • I solved populating those ChoiceField in __init__ with all choiches available, and the populating only the widget choices:

    def __init__(self, *args, **kwargs):
    
        self.fields['city'] = forms.ChoiceField(
            required=False,
        choices=get_all_cities_tuple()
        )   
        self.fields['zip'] = forms.ChoiceField(
        required=False,
        choices=get_all_zips_tuple()
        )
    
    self.fields['city'].widget.choices=get_cities_tuple(region_code=region_code)
    self.fields['city'].initial = my_initial_city_value 
    self.fields['zip'].widget.choices=get_zips_tuple(
                                              region_code=region_code,
                                              city_name=city_name
                                          )
    self.fields['zip'].initial = my_initial_zip_value
    

    While this is not the best approach in term of computational cost, that's what have worked for me for this specific task.