Customize/remove Django select box blank option

后端 未结 15 810
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-30 18:22

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

相关标签:
15条回答
  • 2020-11-30 19:01

    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.

    0 讨论(0)
  • 2020-11-30 19:05

    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.

    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]]
    
    0 讨论(0)
  • 2020-11-30 19:06

    I find SOLUTION!!

    But not for ForeignKey :-)

    Maybe I can help you. I looked in Django source code and discovered that in django.forms.extras.widgets.SelecteDateWidget() is a property called none_value that equals (0, '-----') so I did in my code this

    class StudentForm(ModelForm):
        class Meta:
            this_year = int(datetime.datetime.today().strftime('%Y')) 
            birth_years = []
            years = []
    
            for year in range(this_year - 2, this_year + 3 ):
                years.append(year)
            for year in range(this_year - 60, this_year+2):
                birth_years.append(year)
    
            model = Student
            exclude = ['user', 'fullname']
            date_widget = SelectDateWidget(years=years)
    
            date_widget.__setattr__('none_value', (0, 'THERE WAS THAT "-----" NO THERES THIS:-)'))
            widgets = {
                'beginning': date_widget,
                'birth': SelectDateWidget(years=birth_years),
            }
    
    0 讨论(0)
  • 2020-11-30 19:08

    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

    0 讨论(0)
  • 2020-11-30 19:09

    Haven't tested this, but based on reading Django's code here and here I believe it should work:

    class ThingForm(models.ModelForm):
      class Meta:
        model = Thing
    
      def __init__(self, *args, **kwargs):
        super(ThingForm, self).__init__(*args, **kwargs)
        self.fields['verb'].empty_label = None
    

    EDIT: This is documented, though you wouldn't necessarily know to look for ModelChoiceField if you're working with an auto-generated ModelForm.

    EDIT: As jlpp notes in his answer, this isn't complete - you have to re-assign the choices to the widgets after changing the empty_label attribute. Since that's a bit hacky, the other option that might be easier to understand is just overriding the entire ModelChoiceField:

    class ThingForm(models.ModelForm):
      verb = ModelChoiceField(Verb.objects.all(), empty_label=None)
    
      class Meta:
        model = Thing
    
    0 讨论(0)
  • 2020-11-30 19:13

    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.

    0 讨论(0)
提交回复
热议问题