How to hide the default placeholder on a form

Hi,

I’m working on a ModelForm. When a field is set to blank=False in models.py, the form element appears like this:

This screenshot corresponds to this in models.py:

field1 = models.ForeignKey(
    'SomeModel',
    on_delete=models.CASCADE,
    verbose_name='some verbose name',
    related_name='some_related_name',
    )

Which is how I want it to appear. However, when the model indicates blank=True (which is needed), I have this kind of placeholder default (the “---------”) that I can’t get rid of:

In models.py:

    field2 = models.CharField(
        _('Some label'),
        choices=Some.choices,
        max_length=100,
        blank=True
        )

Is it possible to get the appearance of the first image on a filed where blank is set to True?

See the paragraph immediately before this link - Model field reference | Django documentation | Django

Great, thank you very much Ken!

It works great when dealing with choices written in the models.py file. Would you know if there’s a chance it works when dealing with a ForeignKey reffering to a CharField?

I tried to set the field to null=True, then add a new line in the database table and set it either to null or to an empty content, but without luck so far…

See the empty_label attribute for the ModelChoiceField.

1 Like

Perfect. Thanks again!

How would you do with a ChoiceField on models.py?

The following example doesn’t work:

class MyModel(models.TextChoices):
    YES = '', ('Yes')
    NO = 'No', ('No')
    I_DONT_KNOW = 'I don\'t know', ('I don\'t know')
happy_field = models.CharField(
    ('Are you happy?'),
    choices=MyModel.choices,
    default=False,
    blank=True
    )

default=False + a blank value for one of the choices make it appear correct (= with no “------”) but If the submitter select “Yes”, there’s a validation error.

Edit: the validation error appears when the user select the choice with a blank value (here, “Yes”). The error is “Choose a valid Choice. False isn’t one.” (translated from french)

Should I move the choice class to forms.py and add a ChoiceField directly there?

I believe (but am not sure) that the issue with the null value is that the page isn’t going to return a value for that field from the form. (That’s not a “blank” field, it’s a null field - there isn’t any space between the quotes - not that that makes a difference in this specific case.)

Anyway, without having a chance to look at this myself, my first guess would be to mark that field as “required=False” in the form (not the model).

Thank you for you suggestion.
I believe I’ve just solved the issue by deciding it’s not one :slight_smile:

Fields marked as blank=True in models.py reflect their non-mandatory nature in the survey concepters mind. But as I’ve set their widgets as being radio buttons, the submitter actually need a possibility to change their mind if they first check a button and later decide not to answer. Seems to a pretty good reason to leave the “------” to me.

It didn’t occur to me this way at first, but here again, stating things out loud helped me figure it out. Thanks!

1 Like

Getting back to this, I realize that I actually need to get rid of the "---------" when ForeignKey or TextChoices related fields are marked as blank=True.

The django doc paragraph indicated by Ken on the second post of this thread suggests to add a tuple to the choices containing None. That would work when the form loads a Select widget for this field, but I’d like to use a RadioSelect widget. See the screenshots on the first post of the thread to see what I’m looking for precisely.

models.py

    class Jeunes(models.TextChoices):
        OUI = 'Oui', ('Oui')
        NON = 'Non', ('Non')
    qdem02b = models.CharField(
        ('Question?'),
        choices=Jeunes.choices,
        max_length=10,
        blank=True,
        null=True
        )
    qdem03 = models.ForeignKey(
        'Diplome',
        on_delete=models.CASCADE,
        verbose_name='verbose name',
        related_name='repondant_diplome_opt',
        blank=True,
        null=True
        )

forms.py

class AdherentOptForm(forms.ModelForm):

    class Meta:
        model = RepondantOptionnel
        fields = ['qdem02b','qdem03']
        widgets = {
            'qdem02b': forms.RadioSelect,
            'qdem03': forms.RadioSelect
            }

    def __init__(self, *args, **kwargs):
        kwargs.setdefault('label_suffix', '')
        super(AdherentOptForm, self).__init__(*args, **kwargs)

template.html

<form action="{% url 'adherent' %}" method="post" id="adherentForm">

      <div name="jeunes" class="questionWrapper" id="jeunes">
        {{ form.qdem02b.as_field_group }}
      </div>
      
      <div name="diplome" class="questionWrapper" id="diplome">
        {{ form.qdem03.as_field_group }}
      </div>

</form>

Just to confirm, you’ve actually tried this with the RadioSelect and have seen that it doesn’t work?

Yes, confirmed indeed!

I think what you need to do here would be to define the fields as fields in the form in addition to listing it in the Meta.fields.

Example:

class AdherentOptForm(forms.ModelForm):
    qdem03 = forms.ModelChoiceField(
        widget=RadioSelect, 
        required=False,
        queryset=Diplome.objects.all()
    )
    class Meta:
        model = RepondantOptionnel
        fields = ['qdem02b','qdem03']
        widgets = {
            'qdem02b': forms.RadioSelect,
            }

That works indeed for ForeignKey fields.

As for fields calling choices from model defined TextChoices, I moved the choices to the form and defined the fields in forms.py as well.

Thanks again for your help!