I'm going to be keeping data about competitions in my database. I want to be able to search the competitions by certain criteria - competition type in particular.
Competition types are kept in a tuple. A slightly shortened example:
COMPETITION_TYPE_CHOICES = (
(1, 'Olympic Games'),
(2, 'ISU Championships'),
(3, 'Grand Prix Series'),
)
These are used in the model like so (again - this is a shortened/simplified version of the model):
class Competition(models.Model):
name = models.CharField(max_length=256)
type = models.IntegerField(choices=COMPETITION_TYPE_CHOICES)
I don't want the fields to be required in the search form, so the form is defined like this:
class CompetitionSearchForm(forms.Form):
name = forms.CharField(required=False)
type = forms.ChoiceField(choices=COMPETITION_TYPE_CHOICES,required=False)
I'd like the select widget in ChoiceField to display an empty label, but I don't get one. Any help with this would be much appreciated :)
I've found a solution that works the way I want it to without violating the DRY principle. Not very clean, but it'll have to do I suppose.
According to the documentation choices don't have to be a tuple:
Finally, note that choices can be any iterable object -- not necessarily a list or tuple. This lets you construct choices dynamically. But if you find yourself hacking choices to be dynamic, you're probably better off using a proper database table with a ForeignKey. choices is meant for static data that doesn't change much, if ever.
So the solution I'm going with for the moment is:
COMPETITION_TYPE_CHOICES = [
(1, 'Olympic Games'),
(2, 'ISU Championships'),
(3, 'Grand Prix Series'),
]
COMP_TYPE_CHOICES_AND_EMPTY = [('','All')] + COMPETITION_TYPE_CHOICES
And then:
class CompetitionSearchForm(forms.Form):
name = forms.CharField(required=False)
type = forms.ChoiceField(choices=COMP_TYPE_CHOICES_AND_EMPTY, required=False)
The model stays the same as it was.
I tried both Monika's and Evgeniy's solutions with no success, but Monika has a good point in that the choices do not need to be tuples. Therefore, the easiest (and DRYest) solution is to simply do what Django does already in the Model Field. Simply add the blank choice and the tuples together after converting them to a list:
from django.db.models.fields import BLANK_CHOICE_DASH
...
type = forms.ChoiceField(choices=BLANK_CHOICE_DASH + list(COMPETITION_TYPE_CHOICES), required=False)
Better choice is to update field choices in form init method
COMPETITION_TYPE_CHOICES = (
(1, 'Olympic Games'),
(2, 'ISU Championships'),
(3, 'Grand Prix Series'),
)
class CompetitionSearchForm(forms.Form):
name = forms.CharField(required=False)
type = forms.ChoiceField(choices=COMPETITION_TYPE_CHOICES,required=False)
def __init__(self, *args, **kwargs):
super(CompetitionSearchForm, self).__init__(*args, **kwargs)
self.fields['type'].choices.insert(0, ('','---------' ) )
According to the documentation:
Either an iterable (e.g., a list or tuple) of 2-tuples to use as choices for this field, or a callable that returns such an iterable. (https://docs.djangoproject.com/en/dev/ref/forms/fields/)
So, you can simple:
sample_field = forms.ChoiceField(choices=(('', '---'),) + Model.YOUR_CHOICES)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With