[Django]-How to change empty_label for modelForm choice field?

10👍

The problem is that you are trying to specify something that is not available for the type of Select field.

The empty_label option is for forms.ModelChoiceField, which happens to use a Select widget, but is not the same kind of field as your CharField that you are providing options for.

https://docs.djangoproject.com/en/dev/ref/forms/fields/#modelchoicefield

You can see this also in a previous question here: https://stackoverflow.com/a/740011/1406860

You could try and override the html of the modelform to add the first option as “please choose value”. Alternatively, you could use a template filter to do the same thing. Lastly, you could and (“”, “please choose value”) to PAYROLL_CHOICES, and if you don’t want it to be submitted without a payrollProvider just set blank=False for the field in the model.

JD

16👍

dokkaebi, that won’t work properly. You’ll receive the following select code:

<select name="payrollProvider" id="id_payrollProvider">
<option value="" selected="selected">---------</option>
<option value="" selected="selected">please choose value</option>
<option value="C1">Choice1</option>
<option value="C2">Choice2</option>
</select>

The only relatively convenient way that came to my mind is to do something like this in the form:

class PayrollCredentialForm(forms.ModelForm):
    class Meta:
        model = Company
    def __init__(self, *args, **kwargs):
        super(PayrollCredentialForm, self).__init__(*args, **kwargs)
        self.fields["payrollProvider"].choices = [("", "please choose value"),] + list(self.fields["payrollProvider"].choices)[1:] 

10👍

Actually, now (as of Django 1.8 and higher) override of an empty_label works:

class PayrollCredentialForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(PayrollCredentialForm, self).__init__(*args, **kwargs)
        self.fields['payrollProvider'].empty_label = 'Please, choose value'

Also, if you working with Django Admin, there is an option to set empty value for a list view:

class PayrollCredentialAdmin(admin.ModelAdmin):
    list_display = ('payrollProvider_value', )

    def payrollProvider_value(self, instance):
        return instance.payrollProvider
    payrollProvider_value.empty_value_display = 'Empty value'

What if field should be readonly?

There is a catch if field modified in such way should be readonly.

If overridden form field will be specified in readonly_fields attribute inside PayrollCredentialAdmin class, it would result in KeyError exception in PayrollCredentialForm (because readonly field won’t be included in form’s self.fields). To handle that, it’s required to override formfield_for_dbfield instead of using readonly_fields:

def formfield_for_dbfield(self, db_field, **kwargs):
    field = super(PayrollCredentialAdmin, self).formfield_for_dbfield(
        db_field, **kwargs
    )
    db_fieldname = canonical_fieldname(db_field)

    if db_fieldname == 'payrollProvider':
        field.widget = forms.Select(attrs={
            'readonly': True, 'disabled': 'disabled',
        })

    return field

Might be useful.


Update for Django 1.11:

Comments below brought assumption that such override is no longer valid for newer version of Django.

3👍

In your forms.py file,
This would definitely work.. Try this…

     class Meta:
        model = StaffDetails
        fields =['photo','email', 'first_name','school','department', 'middle_name','last_name','gender', 'is_active']
     def __init__(self, *args, **kwargs):
        super(StaffDetailsForm, self).__init__(*args, **kwargs)
        self.fields['Field_name'].empty_label = 'Please Select' 

It worked for me.. just replace the field names with yours…

👤Javed

1👍

Only ModelChoiceField (generated for ForeignKey fields) supports the empty_label parameter, and in that case it’s tricky to get at as those fields are usually generated by django.forms.models.ModelFormMetaclass within a call to django.forms.models.modelform_factory.

ModelFormMetaclass uses the empty_label param to add another choice to the list, with empty_label as the display and '' as its value.

The simplest way to do what you want is just to add an empty choice to your choices list:

PAYROLL_CHOICES = (
        ('', 'please choose value'),
        ('C1', 'Choice1'),
        ('C2', 'Choice2'),

        etc.....
                    )

1👍

Another simple way worked for me is:

country = forms.ModelChoiceField(queryset=Country.objects.filter(), empty_label='--Select--')

However, my Django version is 2.2.7

1👍

Just add a tuple to your model.field.choices with a value of None:

 payrollProvider = models.CharField(max_length=2, choices=PAYROLL_CHOICES)
 PAYROLL_CHOICES = (
        (None, 'please choose'),
        ('C1', 'Choice1'),
        ('C2', 'Choice2')
        etc.....
                    )

From the docs (v4.0):

Unless blank=False is set on the field along with a default then a label containing "———" will be rendered with the select box. To override this behavior, add a tuple to choices containing None; e.g. (None, ‘Your String For Display’). Alternatively, you can use an empty string instead of None where this makes sense – such as on a CharField.

0👍

Adapted from Javed answer. Since I have tons of fields in my form I just want to replace all labels in the html by placeholders so for select tags I use their field label.

class PacienteForm(forms.ModelForm):

    class Meta:
        model=Paciente
        fields=('__all__')

    def __init__(self, *args, **kwargs):
        super(PacienteForm, self).__init__(*args, **kwargs)

        for f in self.fields:
            if hasattr(self.fields[f], 'choices'):
                choices=self.fields[f].choices
                if type(choices) == list:
                    choices[0]=('',self.fields[f].label)
                    self.fields[f].choices=choices

0👍

Add Empty String with "Please Select" to choices as shown below:

class DateForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        class Months(models.TextChoices):
            EMPTY_LABEL = '', 'Please Select' # Here
            JANUARY = 'JAN', 'January'
            FEBRUARY = 'FEB', 'February'
            MARCH = 'MAR', 'March'
                                 
        self.fields['month'].choices = Months.choices

Leave a comment