Posts tagged with ChoiceField

Django forms ChoiceField and custom HTML output...

Published at Jan. 6, 2011 | Tagged with: , , , ,

... or what to do in case that you need a special design for your choice fields

The problem: Few posts ago I talked(wrote) about Django forms ChoiceField and with dynamic values and now it is time to take a look at the front end and how we display these values to the user. I will use the code from that post:

class MyForm(forms.Form):
    my_choice_field = forms.ChoiceField(choices=MY_CHOICES)
By default Django provide us with a simple drop-down list as visual representation of the choice field. Just create and instance of the form in your view, pass it in the context:
def my_view(request):
    form = MyForm()
    return render_response('template.html',{'form': form})
and then display it in the template using {{form.my_choice_field}}. Speciality: For most cases this drop-down works just fine but sometimes this is not enough. Lets say that instead of drop-down list we need a radio buttons. There are two ways to achieve this - using a custom widget or playing with the template tags and the ChoiceField object. The first solutions is more suitable if you have a repeatable interface for several fields. In my case this was field specific so I chose the second one as faster for implementation. Solution: You can access the field object and its choices calling the field respectively field.choices properties of the form element in the template. Here is an example
<ul>
{% for choice in form.my_choice_field.field.choices %}
  <li>
    <input type="radio" name="my_choice_field" value="{{choice.0}}"
      {% ifequal form.my_choice_field.data choice.0 %} 
         checked="checked"
      {% endifequal %}/>
    <label for="">{{choice.1}}</label>
  </li>
{% endfor %}
</ul>

This allows you to specify custom styles/HTML for every element and also to distinct first and last elements using forloop.first and forloop.last - for more information you can check Django documentation about the for template tag

Final words: I did not have the chance to measure the speed difference between these two methods I mentions but I intend to post a also an example of the first one(using custom widget) and a "benchmark" between them both. If someone has already done this please post the results and your opinion about this.

Django forms ChoiceField with dynamic values...

Published at Dec. 5, 2010 | Tagged with: , , , ,

... or how to get a dynamic drop-down list with Django forms

The problem: Lets say that you need a form with a drop-down list that have dynamic values. With Django this can be done simple and fast, but if you are new you may get yourself into a trap. In a standard form(with static values in the drop-down) your code will be something like this:

MY_CHOICES = (
    ('1', 'Option 1'),
    ('2', 'Option 2'),
    ('3', 'Option 3'),
)
    
class MyForm(forms.Form):
    my_choice_field = forms.ChoiceField(choices=MY_CHOICES)
So if you want the values to be dynamic(or dependent of some logic) you can simply modify your code to something like this:
def get_my_choices():
    # you place some logic here
    return choices_list

class MyForm(forms.Form):
    my_choice_field = forms.ChoiceField(choices=get_my_choices())
and here you will fail(not absolutely). This is a common mistake and sooner or later you will see what you messed but it my be too late. Speciality: the trick is that in this case my_choice_field choices are initialized on server (re)start. Or in other words once you run the server the choices are loaded(calculated) and they will not change until next (re)start. This mean that your logic will be executed only once. This will be OK if your logic is server specific(depends from server settings) or "semi-dynamic" in any other way. But you need this list to be updated on every form load you will need to use something the form __init__ method. Solution: fortunately the form`s class has an __init__ method that is called on every form load. Most of the times you skipped it in the form definition but now you will have to use it.
def get_my_choices():
    # you place some logic here
    return choices_list

class MyForm(forms.Form):
    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.fields['my_choice_field'] = forms.ChoiceField(
            choices=get_my_choices() )

You first call the __init__ method of the parent class(Form) using the super keyword and then declare your dynamic fields(in this case my_choice_field). With this code get_my_choices is called on every form load and you will get your dynamic drop-down.

Final words: have in mind that this method also have one strong drawback. If your application have a heavy load, executing a logic on every form load may(will) bring you troubles. So some caching of the form or the logic result may be useful.
And remember If you have other approach, idea or question I am always ready to hear it.