I\'m using Django 1.0.2. I\'ve written a ModelForm backed by a Model. This model has a ForeignKey where blank=False. When Django generates HTML for this form it creates a
I was messing around with this today and just came up with a coward hack nifty solution:
# Cowardly handle ModelChoiceField empty label
# we all hate that '-----' thing
class ModelChoiceField_init_hack(object):
@property
def empty_label(self):
return self._empty_label
@empty_label.setter
def empty_label(self, value):
self._empty_label = value
if value and value.startswith('-'):
self._empty_label = 'Select an option'
ModelChoiceField.__bases__ += (ModelChoiceField_init_hack,)
Now you can tweak the default ModelChoiceField
empty label to anything you'd like. :-)
PS: No need for downvotes, non-harmful monkey patches are always handy.
There are lots of great answers here, but I'm still not entirely satisfied with the implementations. I'm also a bit frustrated that select widgets from different sources (foreign keys, choices) yield different behaviours.
I have a design I'm working with where select fields always have a blank option, and if they're required they will have a star next to them and the form will simply not validate if they're left empty. That said, I can only properly override the empty_label for fields that are not TypedChoiceField
s.
Here's what the result should look like. The first result is always the name of the field - in my case, the label
.
Here's what I ended up doing. The following is an overridden __init__
method of my form:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for _, field in self.fields.items():
if hasattr(field, 'empty_label'):
field.empty_label = field.label
if isinstance(field, forms.TypedChoiceField):
field.choices = [('', field.label)] + [choice for choice in field.choices if choice[0]]
I find SOLUTION!!
But not for ForeignKey :-)
Maybe I can help you. I looked in Django source code and discovered that in django.forms.extras.widgets.SelecteDateWidget() is a property called none_value that equals (0, '-----') so I did in my code this
class StudentForm(ModelForm):
class Meta:
this_year = int(datetime.datetime.today().strftime('%Y'))
birth_years = []
years = []
for year in range(this_year - 2, this_year + 3 ):
years.append(year)
for year in range(this_year - 60, this_year+2):
birth_years.append(year)
model = Student
exclude = ['user', 'fullname']
date_widget = SelectDateWidget(years=years)
date_widget.__setattr__('none_value', (0, 'THERE WAS THAT "-----" NO THERES THIS:-)'))
widgets = {
'beginning': date_widget,
'birth': SelectDateWidget(years=birth_years),
}
from the docs
The blank choice will not be included if the model field has blank=False and an explicit default value (the default value will be initially selected instead).
so set the default and you're ok
Haven't tested this, but based on reading Django's code here and here I believe it should work:
class ThingForm(models.ModelForm):
class Meta:
model = Thing
def __init__(self, *args, **kwargs):
super(ThingForm, self).__init__(*args, **kwargs)
self.fields['verb'].empty_label = None
EDIT: This is documented, though you wouldn't necessarily know to look for ModelChoiceField if you're working with an auto-generated ModelForm.
EDIT: As jlpp notes in his answer, this isn't complete - you have to re-assign the choices to the widgets after changing the empty_label attribute. Since that's a bit hacky, the other option that might be easier to understand is just overriding the entire ModelChoiceField:
class ThingForm(models.ModelForm):
verb = ModelChoiceField(Verb.objects.all(), empty_label=None)
class Meta:
model = Thing
For a ForeignKey
field, setting the default
value to ''
on the model will remove the blank option.
verb = models.ForeignKey(Verb, on_delete=models.CASCADE, default='')
For other fields like CharField
you could set the default
to None
, but this does not work for ForeignKey
fields in Django 1.11.