Dynamic selection for Django SelectMultiple Widget

I am creating a form (not modelForm) where I would like to use the SelectMultiple Widget widget to display options based on a request made during form initialization.

I can come up with several ways to do this, but I don’t quite understand how to do it right. I see different options.

I get the "choices" that I have to pass to the widget in the form of init , but I'm not sure how to pass them to me.

class NavigatorExportForm(forms.Form): def __init__(self,user, app_id, *args,**kwargs): super (NavigatorExportForm,self ).__init__(*args,**kwargs) # populates the form language_choices = Navigator.admin_objects.get(id=app_id).languages.all().values_list('language', flat=True) languages = forms.CharField(max_length=2, widget=forms.SelectMultiple(choices=???language_choices)) 
+4
source share
2 answers

Why not use ModelMultipleChoiceField instead?

You can do it simply:

 class NavigatorExportForm(forms.Form): languages = forms.ModelMultipleChoiceField(queryset=Language.objects.all()) def __init__(self, app_id, *args, **kwargs): super(NavigatorExportForm, self).__init__(*args, **kwargs) # Dynamically refine the queryset for the field self.fields['languages'].queryset = Navigator.admin_objects.get(id=app_id).languages.all() 

Thus, you not only restrict access to the widget, but also in the field (which gives you confirmation of the data).

Using this method, the displayed string in the widget will be the result of the __unicode__ method of the __unicode__ object. If this is not what you want, you can write the following custom field, as described in the ModelChoiceField link :

 class LanguageMultipleChoiceField(forms.ModelMultipleChoiceField): def label_from_instance(self, obj): return obj.language_code # for example, depending on your model 

and use this class instead of ModelMultipleChoiceField in your form.

+6
source
 def __init__(self,user, app_id, *args,**kwargs): super (NavigatorExportForm,self ).__init__(*args,**kwargs) self.fields['languages'].widget.choices = Navigator.admin_objects.get(id=app_id).languages.all().values_list('language', flat=True) 

seems to do the trick, but without even specifying max_length, the widget displays only the first letter of the selection ...

0
source

Source: https://habr.com/ru/post/1306712/


All Articles