Customize/remove Django select box blank option

2019-01-08 05:13发布

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 select box with one option for each row in the table referenced by the ForeignKey. It also creates an option at the top of the list that has no value and displays as a series of dashes:

<option value="">---------</option>

What I'd like to know is:

  1. What is the cleanest way to remove this auto-generated option from the select box?
  2. What is the cleanest way to customize it so that it shows as:

    <option value="">Select Item</option>
    

In searching for a solution I came across Django ticket 4653 which gave me the impression that others had the same question and that the default behavior of Django may have been modified. This ticket is over a year old so I was hoping there might be a cleaner way to accomplish these things.

Thanks for any help,

Jeff

Edit: I've configured the ForeignKey field as such:

verb = models.ForeignKey(Verb, blank=False, default=get_default_verb)

This does set the default so that it's no longer the empty/dashes option but unfortunately it doesn't seem to resolve either of my questions. That is, the empty/dashes option still appears in the list.

15条回答
放我归山
2楼-- · 2019-01-08 05:13

you can do this in admin:

formfield_overrides = {
    models.ForeignKey: {'empty_label': None},
}
查看更多
叼着烟拽天下
3楼-- · 2019-01-08 05:16

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

查看更多
一纸荒年 Trace。
4楼-- · 2019-01-08 05:18

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.

查看更多
欢心
5楼-- · 2019-01-08 05:21

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.

查看更多
混吃等死
6楼-- · 2019-01-08 05:26

For the latest version of django the first answer should be like this

class ThingForm(models.ModelForm):
class Meta:
 model = Thing

  def __init__(self, *args, **kwargs):
    self.base_fields['cargo'].empty_label = None
    super(ThingForm, self).__init__(*args, **kwargs)`
查看更多
放荡不羁爱自由
7楼-- · 2019-01-08 05:28

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 TypedChoiceFields.

Here's what the result should look like. The first result is always the name of the field - in my case, the label.

select widget

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]]
查看更多
登录 后发表回答