11

I am using ModelForm on Django 1.3.

models.py:

class UserProfile(models.Model):
...
gender = models.CharField(max_length=1, blank=True, choices=(('M', 'Male'), ('F', 'Female'), ('Unspecified', '')), default='M')
...

forms.py:

class UserProfileForm(ModelForm):
    class Meta:
        model = UserProfile
        fields = ('gender')
        widgets = {
            'gender': forms.RadioSelect(),
        }

When this widget is rendered into HTML, I got

<ul> 
<li><label for="id_gender_0"><input type="radio" id="id_gender_0" value="" name="gender" />---------</label></li> 
<li><label for="id_gender_1"><input checked="checked" type="radio" id="id_gender_1" value="M" name="gender" /> Male</label></li> 
<li><label for="id_gender_2"><input type="radio" id="id_gender_2" value="F" name="gender" />Female</label></li> 
<li><label for="id_gender_3"><input type="radio" id="id_gender_3" value="" name="gender" /> Unspecified</label></li> 
</ul> 

Problem: How can I get rid of the bogus choice "--------"?

The same problem was brought up by another stackoverflow user months ago (Here). I have tried the accepted solution in there (as you can see) but that didn't work for me.

Community
  • 1
  • 1
tamakisquare
  • 16,659
  • 26
  • 88
  • 129

5 Answers5

9

Even without blank=True it shows the extra input. I have created a new Widget:

from itertools import chain
from django.forms import RadioSelect
from django.utils.encoding import force_unicode

class RadioSelectNotNull(RadioSelect):
    def get_renderer(self, name, value, attrs=None, choices=()):
        """Returns an instance of the renderer."""
        if value is None: value = ''
        str_value = force_unicode(value) # Normalize to string.
        final_attrs = self.build_attrs(attrs)
        choices = list(chain(self.choices, choices))
        if choices[0][0] == '':
            choices.pop(0)
        return self.renderer(name, str_value, final_attrs, choices)
freyley
  • 4,145
  • 3
  • 20
  • 25
NickJ
  • 104
  • 1
  • 4
6

Set blank=False (or just remove it) and also add default='Unspecified'

frnhr
  • 12,354
  • 9
  • 63
  • 90
1

By default the widget used by ModelChoiceField will have an empty choice at the top of the list.

You can change the text of this label (which is "---------" by default) with the empty_label attribute, or you can disable the empty label entirely by setting empty_label to None:

A custom empty label:

field1 = forms.ModelChoiceField(queryset=..., empty_label="(Nothing)")

No empty label:

field2 = forms.ModelChoiceField(queryset=..., empty_label=None)
Deepend
  • 4,057
  • 17
  • 60
  • 101
violenttom
  • 41
  • 1
  • 3
1

You can set the choices when you set the widget. It's showing the ---- because in your model you have blank=True.

Just use the choices arg of the widget and set it to the choices you set in your model.

dting
  • 38,604
  • 10
  • 95
  • 114
0

Django <= 1.10

RadioSelectNotNull widget

from itertools import chain
from django.forms import RadioSelect
from django.utils.encoding import force_unicode

class RadioSelectNotNull(RadioSelect):
"""
A widget which removes the default '-----' option from RadioSelect
"""
    def get_renderer(self, name, value, attrs=None, choices=()):
        """Returns an instance of the renderer."""
        if value is None: value = ''
        str_value = force_unicode(value) # Normalize to string.
        final_attrs = self.build_attrs(attrs)
        choices = list(chain(self.choices, choices))
        if choices[0][0] == '':
            choices.pop(0)
        return self.renderer(name, str_value, final_attrs, choices)

Django >= 1.11

As after Django 1.10 following method is no more in RadioSelect or in its ancestors. That's why upper widget will not remove bogus choice generated by RadioSelect.

def get_renderer(self, name, value, attrs=None, choices=()):

So to remove bogus choice generated by RadioSelect use following widget. I have tested this till Django 2.0

from django.forms import RadioSelect
class RadioSelectNotNull(RadioSelect):
    """
    A widget which removes the default '-----' option from RadioSelect
    """
    def optgroups(self, name, value, attrs=None):
        """Return a list of optgroups for this widget."""
        if self.choices[0][0] == '':
            self.choices.pop(0)
        return super(RadioSelectNotNull, self).optgroups(name, value, attrs)