How to change the empty_label value in Django's ModelChoiceField?

In Django, I’m using a ModelChoiceField with the empty_label parameter to allow users to unselect a value in a dropdown. Here’s the code:

department = forms.ModelChoiceField(
    queryset=Department.objects.all(),
    label="Department",
    required=False,
    empty_label="------"  # Add an empty option
)

This works fine, but the default behavior assigns an empty string ("") as the value for the empty_label option. Unfortunately, one of the JavaScript libraries I’m using does not handle empty string values properly.

I need to assign a custom value (e.g., -1) for the empty_label option, but I still want to retain its functionality to "unselect" the current object.

I’ve tried overriding the choices in the init method, like this:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.fields['department'].widget.choices = [("-1", "------")] + list(
        self.fields['department'].queryset.values_list('id', 'name')
    )

However, when I do this, the functionality doesn’t work as expected — it doesn’t allow the "unselect" option as it does with the empty_label.

How can I change the empty_label value (from the empty string) to -1 and still maintain the same behavior of unselecting the option?

Thanks in advance for your help!

You could write your own with a patch of the ModelChoiceIterator:

from django.forms.models import ModelChoiceIterator


class MyModelChoiceIterator(ModelChoiceIterator):
    def __iter__(self):
        if self.field.empty_label is not None:
            yield ('-1', self.field.empty_label)
        queryset = self.queryset
        if not queryset._prefetch_related_lookups:
            queryset = queryset.iterator()
        for obj in queryset:
            yield self.choice(obj)

Then plug this in as in a subclass of ModelChoiceField: MyModelChoiceField:

from django.forms.models import ModelChoiceField


class MyModelChoiceField(ModelChoiceField):
    iterator = MyModelChoiceIterator
    empty_values = [*ModelChoiceField.empty_values, '-1']

and then plug in this model field in your form.

Back to Top