Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django modelchoicefield with distinct column values

Tags:

python

django

What I'd like to do is populate a select element with distinct values from one column in the model table.

my forms.py:

class ExampleForm(forms.ModelForm):
    only_unique_values = forms.ModelChoiceField(
        required = False,
        queryset = ReadOnlyTable.objects.values('pie').distinct(),
        widget = forms.Select
    )

Using the values function returns a ValuesQuerySet instead of a QuerySet, which is a problem for my select element because all the options are populated with the dictionary syntax as the values instead of just the column data as strings.

It ends up looking like this:

<select id="id_example" name="example_form">
<option value="" selected="selected">---------</option>
<option value="{'pie': u'apple     '}">{'pie': u'apple     '}</option>
<option value="{'pie': u'pecan     '}">{'pie': u'pecan     '}</option>
<option value="{'pie': u'dutch     '}">{'pie': u'dutch     '}</option>
<option value="{'pie': u'pumpkin     '}">{'pie': u'pumpkin     '}</option>
</select>

How I would want it to look is like so:

<select id="id_example" name="example_form">
<option value="" selected="selected">---------</option>
<option value="apple">apple</option>
<option value="pecan">pecan</option>
<option value="dutch">dutch</option>
<option value="pumpkin">pumpkin</option>
</select>

How can I return string values from a distinct() call on my model?

like image 995
smilebomb Avatar asked Sep 26 '22 05:09

smilebomb


1 Answers

A model choice field is for selecting instances from your model. If you are selecting values from the model instances, then a model choice field isn't suitable any more.

You can use a choice field instead, and set the choices in the form's __init__ method.

class ExampleForm(forms.ModelForm):
    only_unique_values = forms.ChoiceField(
        required=False,
        choices=[],
        widget=forms.Select,
    )

    def __init__(self, *args, **kwargs):
        super(ExampleForm, self).__init__(*args, **kwargs)
        self.fields['only_unique_values'].choices = ReadOnlyTable.objects.values_list('pie', 'pie').distinct()

Doing values_list('pie', 'pie') give you the list of two-tuples required by the choice field.

In Django 1.8+, you don't need to override __init__ any more. Instead, you can define a callable that returns the list of choices, and pass the callable to your choice field.

def unique_values():
    return ReadOnlyTable.objects.values_list('pie', 'pie').distinct()

class ExampleForm(forms.ModelForm):
    only_unique_values = forms.ChoiceField(
        required=False,
        choices=unique_values,
        widget=forms.Select,
    )

To include a blank option in your choice field, just add an item to the list of choices:

def unique_values():
    return [("", "---------")] + list(ReadOnlyTable.objects.values_list('pie', 'pie').distinct())
like image 196
Alasdair Avatar answered Sep 28 '22 05:09

Alasdair