Tutorial :Add an “empty” option to a ChoiceField based on model datas



Question:

I'm defining a ChoiceField based on a model's datas.

field = forms.ChoiceField(choices=[[r.id, r.name] for r in Model.objects.all()])  

However I'd like to prepend my options with an empty one to select "no" objects. But I can't find a nice way to prepend that.

All my tests like :

field = forms.ChoiceField(choices=[[0, '----------']].extend([[r.id, r.name] for r in Model.objects.all()]))  

Returns me a "NoneType object not iterable" error. The only way I've found until now is the following :

def append_empty(choices):      ret = [[0, '----------']]      for c in choices:          ret.append(c)     return ret  

And when I define my field :

forms.ChoiceField(choices=append_empty([[r.id, r.name] for r in      Restaurant.objects.all()]), required=False)  

However I'd like to keep my code clean and not have that kind of horrors. Would you have an idea for me ? :p Thanks by advance.


Solution:1

An easy answer is to do:

field = forms.ChoiceField(choices=[[0, '----------']] + [[r.id, r.name] for r in Model.objects.all()])  

Unfortunately, your approach is flawed. Even with your 'working' approach, the field choices are defined when the form is defined, not when it is instantiated - so if you add elements to the Model table, they will not appear in the choices list.

You can avoid this by doing the allocation in the __init__ method of your Form.

However, there is a much easier approach. Rather than messing about with field choices dynamically, you should use the field that is specifically designed to provide choices from a model - ModelChoiceField. Not only does this get the list of model elements dynamically at instantiation, it already includes a blank choice by default. See the documentation.


Solution:2

Since this question and its answer almost solved a problem I just had I'd like to add something. For me, the id had to be empty because the model didn't recognise '0' as a valid option, but it accepted empty (null=True, blank=True). In the initializer:

self.fields['option_field'].choices = [      ('', '------')] + [[r.id, r.name] for r in Model.objects.all()]   

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »