How to change empty_label for modelForm choice field?
Asked Answered
I

9

19

I have a field in one of my models like the following:

PAYROLL_CHOICES = (
    ('C1', 'Choice1'),
    ('C2', 'Choice2')
    etc.....
)

payrollProvider = models.CharField(max_length=2, choices=PAYROLL_CHOICES)

When I create a model form for this field, Django correctly generates an HTML select box, but includes a default blank value of "---------".

I would like to know how to change this default value to some other text, such as "please choose value".

I believe I should be able to set this in my model form's init via the following, as documented in this answer and several others:

self.fields['payrollProvider'].empty_label = "please choose value"

However, this isn't working for me. When I include that line in my form's init, "--------" still shows up as the initial choice in the select box. I'm pasting the relevant forms.py below, but it seems that others have also been unable to access / modify empty_label. At this link, the questioner describes a way to delete the default empty_label value (which I was able to do successfully via his method) but what I really want to do is to modify the empty_label that is displayed.

Any ideas?

Here's the code for the form in forms.py, with the empty_label code that isn't successful at changing the default "----------":

class PayrollCredentialForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(PayrollCredentialForm, self).__init__(*args, **kwargs)
        self.fields['payrollUsername'].widget.attrs.update({'class' : 'yp-signup'})
        self.fields['payrollPassword'].widget.attrs.update({'class' : 'yp-signup'})
        self.fields['payrollProvider'].widget.attrs.update({'class' : 'yp-signup'})
        self.fields['payrollUsername'].widget.attrs.update({'placeholder' : '  Payroll Username'})
        self.fields['payrollPassword'].widget.attrs.update({'placeholder' : '  Payroll Password'})
        self.fields['payrollProvider'].empty_label = "please choose value"


class Meta:
    model = Company
    fields = ('payrollProvider', 'payrollUsername', 'payrollPassword')
    widgets = {
        'payrollPassword': forms.PasswordInput(),
    }
Incontinent answered 20/10, 2012 at 0:4 Comment(0)
W
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://mcmap.net/q/240091/-customize-remove-django-select-box-blank-option

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

Warrantable answered 20/10, 2012 at 1:20 Comment(0)
P
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:] 
Pinette answered 25/12, 2012 at 16:36 Comment(1)
A lifesaver after 3 hours of banging my head against a wall. Changing the blank label looks to be possible in 1.7.Clipboard
W
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://mcmap.net/q/240091/-customize-remove-django-select-box-blank-option

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

Warrantable answered 20/10, 2012 at 1:20 Comment(0)
P
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.

Privilege answered 29/11, 2016 at 14:39 Comment(3)
Strange, it worked for me on Django 1.9 (not tested specifically 1.9.7 though). Upvotes confirmed that this is a working solution. Maybe you've made a mistake somewhere in the code?Privilege
Can you Post the whole Form (including the field you used) for comparsion? I solved it over adding an empty choice buts it kind of annoying since ModelChoice has that option (and it works)Teplitz
confirmed this doesn't work for me either (in django 1.11) I had to use pythonpro's answer instead.Suzan
F
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...

Froghopper answered 26/5, 2017 at 7:3 Comment(0)
I
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.....
                    )
Innings answered 20/10, 2012 at 1:14 Comment(0)
D
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

Degenerate answered 24/5, 2020 at 8:36 Comment(0)
W
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.

Whelk answered 26/12, 2021 at 13:26 Comment(0)
O
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
Ora answered 5/8, 2021 at 9:39 Comment(0)
S
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
Socialize answered 11/6, 2022 at 17:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.