【问题标题】:How to change empty_label for modelForm choice field?如何更改 modelForm 选择字段的 empty_label?
【发布时间】:2012-10-10 15:27:54
【问题描述】:

我的一个模型中有一个字段,如下所示:

 payrollProvider = models.CharField(max_length=2, choices=PAYROLL_CHOICES)
 PAYROLL_CHOICES = (
        ('C1', 'Choice1'),
        ('C2', 'Choice2')
        etc.....
                    )

当我为此字段创建模型表单时,Django 正确生成了一个 HTML 选择框,但包含一个默认的空白值“---------”。

我想知道如何将此默认值更改为其他一些文本,例如“请选择值”。

我相信我应该能够通过以下方式在我的模型表单的 init 中设置它,如 in this answer 和其他几个文档所述:

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

但是,这对我不起作用。当我在表单的 init 中包含该行时,“--------”仍然显示为选择框中的初始选项。我在下面粘贴相关的forms.py,但似乎其他人有also been unable to access / modify empty_label。在这个链接上,提问者描述了一种删除默认empty_label值的方法(我能够通过他的方法成功地做到这一点)但我真正想做的是修改 显示的 empty_label。

有什么想法吗?

这是 forms.py 中表单的代码,其中的 empty_label 代码无法成功更改默认“----------”:

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(),
    }

【问题讨论】:

    标签: django django-forms


    【解决方案1】:

    只有ModelChoiceField(为ForeignKey 字段生成)支持empty_label 参数,在这种情况下很难理解,因为这些字段通常由django.forms.models.ModelFormMetaclass 在对django.forms.models.modelform_factory 的调用中生成。

    ModelFormMetaclass 使用empty_label 参数将另一个选项添加到列表中,empty_label 作为显示,'' 作为其值。

    做你想做的最简单的方法就是在你的选择列表中添加一个空选项:

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

    【讨论】:

      【解决方案2】:

      问题在于您尝试指定的内容不适用于 Select 字段的类型。

      empty_label 选项适用于 forms.ModelChoiceField,它恰好使用 Select 小部件,但与您为其提供选项的 CharField 不同。

      https://docs.djangoproject.com/en/dev/ref/forms/fields/#modelchoicefield

      您也可以在上一个问题中看到这一点:https://stackoverflow.com/a/740011/1406860

      您可以尝试覆盖模型表单的 html 以将第一个选项添加为“请选择值”。或者,您可以使用模板过滤器来做同样的事情。最后,您可以 and ("", "please choose value") 为 PAYROLL_CHOICES,如果您不希望在没有 payrollProvider 的情况下提交它,只需在模型中的字段设置空白 = False。

      京东

      【讨论】:

        【解决方案3】:

        dokkaebi,这将无法正常工作。您将收到以下选择代码:

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

        我想到的唯一相对方便的方法是在表单中做这样的事情:

        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:] 
        

        【讨论】:

        • 将我的头撞到墙上 3 小时后的救星。在 1.7 中更改空白标签似乎是可能的。
        【解决方案4】:

        实际上,现在(从 Django 1.8 及更高版本开始)覆盖 empty_label 有效:

        class PayrollCredentialForm(forms.ModelForm):
            def __init__(self, *args, **kwargs):
                super(PayrollCredentialForm, self).__init__(*args, **kwargs)
                self.fields['payrollProvider'].empty_label = 'Please, choose value'
        

        此外,如果您使用 Django Admin,则可以选择为列表视图设置空值:

        class PayrollCredentialAdmin(admin.ModelAdmin):
            list_display = ('payrollProvider_value', )
        
            def payrollProvider_value(self, instance):
                return instance.payrollProvider
            payrollProvider_value.empty_value_display = 'Empty value'
        

        如果字段应该是readonly

        如果以这种方式修改的字段应该是readonly,则有一个问题。

        如果将在PayrollCredentialAdmin 类中的readonly_fields 属性中指定覆盖的表单字段,则会导致PayrollCredentialForm 中的KeyError 异常(因为readonly 字段不会包含在表单的self.fields 中) .为了解决这个问题,需要覆盖formfield_for_dbfield 而不是使用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
        

        可能有用。


        Django更新1.11:

        下面的评论带来了这样的假设,即这种覆盖对于较新版本的 Django 不再有效。

        【讨论】:

        • 奇怪,它在 Django 1.9 上对我有用(虽然没有专门测试 1.9.7)。 Upvotes 确认这是一个可行的解决方案。也许你在代码的某个地方犯了错误?
        • 您可以发布整个表格(包括您使用的字段)进行比较吗?我通过添加一个空选项解决了这个问题,但它有点烦人,因为 ModelChoice 有这个选项(并且它有效)
        • 确认这对我也不起作用(在 django 1.11 中)我不得不改用 pythonpro 的答案。
        【解决方案5】:

        在您的 forms.py 文件中, 这肯定行得通..试试这个...

             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' 
        

        它对我有用.. 只需将字段名称替换为您的...

        【讨论】:

          【解决方案6】:

          另一个对我有用的简单方法是:

          country = forms.ModelChoiceField(queryset=Country.objects.filter(), empty_label='--Select--')
          

          但是,我的 Django 版本是 2.2.7

          【讨论】:

            【解决方案7】:

            改编自Javed 答案。由于我的表单中有大量字段,我只想用占位符替换 html 中的所有标签,因此对于选择标签,我使用它们的字段标签。

            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
            

            【讨论】:

              【解决方案8】:

              只需向您的 model.field.choices 添加一个值为 None 的元组:

               payrollProvider = models.CharField(max_length=2, choices=PAYROLL_CHOICES)
               PAYROLL_CHOICES = (
                      (None, 'please choose'),
                      ('C1', 'Choice1'),
                      ('C2', 'Choice2')
                      etc.....
                                  )
              

              来自docs (v4.0)

              除非在字段上设置了空白=假以及默认值,否则将使用选择框呈现包含“---------”的标签。 要覆盖此行为,请在包含 None 的选项中添加一个元组;例如(无,“您的显示字符串”)。或者,您可以在有意义的情况下使用空字符串而不是 None - 例如在 CharField 上。

              【讨论】:

                猜你喜欢
                • 2017-10-22
                • 2016-11-08
                • 2019-02-17
                • 1970-01-01
                • 2011-12-14
                • 2012-04-23
                • 1970-01-01
                • 1970-01-01
                • 2015-08-11
                相关资源
                最近更新 更多