views:

176

answers:

2

I'm building a form (not modelForm) where i'd like to use the SelectMultiple Widget to display choices based on a query done during the init of the form.

I can think of a few way to do this but I am not exactly clear on the right way to do it. I see different options.

I get the "choices" I should pass to the widget in the form init but I am not sure how I should pass them.

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))
A: 
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)

that seems to do the trick, but even by not specifying a max_length, the widget only display the first letter of the choices...

PhilGo20
choices must be the list/tuple of following tuples (int_or_str_key, 'name')
alex vasi
for got about that thanks
PhilGo20
+2  A: 

Why not use a ModelMultipleChoiceField instead?

You could do simply this :

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()

This way you don't only restrict the choices available on the widget, but also on the field (that gives you data validation).

With this method, the displayed string in the widget would be the result of the __unicode__ method on a Language object. If it's not what you want, you could write the following custom field, as documented in ModelChoiceField reference :

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.

Clément
I had seen mention of the ModelMultipleChoiceField, but wasn't sure of the use. Trying that right now. thanks.
PhilGo20
works perfectly and seem a little cleaner than mine.thanks again
PhilGo20
mmm actually, I get a "AttributeError: 'unicode' object has no attribute 'get'" when validating the form. My language model is indeed a char field...
PhilGo20
You have to provide more detail on this error, in which file is it happening? What's the context? Might it come from the way you clean or manipulate cleaned data in the form? Also, what do you mean by : _my language model is indeed a char field..._?
Clément