【问题标题】:How do I set default widget attributes for a Django ModelForm?如何为 Django ModelForm 设置默认小部件属性?
【发布时间】:2011-04-10 09:58:26
【问题描述】:

我想将 TextInput 小部件的类属性设置为表单中所有使用它的字段的一个值,而不必在 Meta 中将它们全部列出:widgets = {...。这可能吗?

谢谢。

【问题讨论】:

    标签: django django-forms


    【解决方案1】:

    使用您的 CSS 类创建一个新小部件:

    class PrettyWidget(forms.TextInput):
        class Media:
            css = {
                'all': ('pretty.css',)
            }
    

    在您的表单中,在所有字段中使用您的新小部件:

    class ContactForm(forms.Form):
        subject = TextField(widget=PrettyWidget)
    

    【讨论】:

    • 这感觉更像是 Djangonic 完成任务的方式,但对我来说,这似乎不像 Kevin 所追求的......
    【解决方案2】:

    我过去做过的一件事是创建一个 lambda 函数来返回我经常使用的字段:

    from django import forms
    
    fancy = lambda: forms.TextInput(attrs={'class': 'derp'})
    
    class MyForm(forms.Form):
        attr1 = fancy()
        attr2 = fancy()
        attr3 = fancy()
    

    我不记得为什么我选择使用函数来处理我的情况,但我怀疑它与为每个表单字段创建单独的 forms.TextInput 对象实例有关......

    【讨论】:

    • 这就是我现在所做的。有必要创建单独的 forms.Select 实例。
    【解决方案3】:

    您可以使用以下内容:

    def set_attrs_for_fields(fields, default_attrs):
        for field_name in fields:
            field = fields[field_name]
    
            try:
                default_widget_attr = default_attrs[field.widget.__class__]
                field.widget.attrs = default_widget_attr
            except KeyError:
                pass
    
    
    class DefaultAttrForm(forms.Form):
    
        def __init__(self, *args, **kwargs):
    
            super(DefaultAttrForm, self).__init__(*args, **kwargs)
    
            set_attrs_for_fields(self.fields, self.get_default_attrs())
    
    
        def get_default_attrs(self):
            '''
            Child class should overwrite this method and return dict with example format
    
            {forms.TextInput: {'class': 'my_value'}}
    
            where keys, are widget classes for which default attrs will be set. 
            '''
            raise NotImplementedError()
    
    
    class DefaultAttrModelForm(ModelForm):
    
        def __init__(self, *args, **kwargs):
    
            super(DefaultAttrModelForm, self).__init__(*args, **kwargs)
    
            set_attrs_for_fields(self.fields, self.get_default_attrs())
    
    
        def get_default_attrs(self):
            '''
            Child class should overwrite this method and return dict with example format
    
            {forms.TextInput: {'class': 'my_value'}}
    
            where keys, are widget classes for which default attrs will be set. 
            '''
            raise NotImplementedError() 
    

    现在,每次您想为某些小部件使用默认属性时,您只需创建继承自 DefaultAttrForm 或 DefaultAttrModelForm 的类并覆盖方法 get_default_attrs。普通 Django 表单示例:

    class MyForm(DefaultAttrForm):
        my_field1 = forms.CharField(widget=forms.TextInput())
        my_field2 = forms.CharField(widget=forms.PasswordInput(attrs={'my_non_default': 'Non default'}))
    
        def get_default_attrs(self):
            # all fields with widget TextInput will have 
            # default attrs set to {'class': 'my_value'}
    
            return {forms.TextInput: {'class': 'my_value'},
                   }
    
    
    In [1]: form = MyForm()
    
    In [2]: form.fields['my_field1'].widget.attrs
    Out[2]: {'class': 'my_value'}
    
    In [3]: form.fields['my_field2'].widget.attrs
    Out[3]: {'my_non_default': 'Non default'}
    

    对于模型表单,请使用以下内容:

    class MyModelForm(DefaultAttrModelForm):
    
        class Meta:
            model = my_model
    
        def get_default_attrs(self):
            # all fields with widget TextInput will have 
            # default attrs set to {'class': 'my_value'}
    
            return {forms.TextInput: {'class': 'my_value'},
                   }
    
    
    In [1]: form = MyModelForm()
    
    In [2]: form.fields['my_field1'].widget.attrs
    Out[2]: {'class': 'my_value'}
    
    In [3]: form.fields['my_field2'].widget.attrs
    Out[3]: {'my_non_default': 'Non default'}
    

    【讨论】:

      【解决方案4】:

      您可以重写构造函数以修改所有 TextInput 小部件:

      from django import forms
      
      class MyForm(forms.ModelForm):
          def __init__(self, *args, **kwargs):
              super(MyForm, self).__init__(*args, **kwargs)
              for name, field in self.fields.items():
                  if field.widget.__class__ == forms.widgets.TextInput:
                      if 'class' in field.widget.attrs:
                          field.widget.attrs['class'] += ' my-class'
                      else:
                          field.widget.attrs.update({'class':'my-class'})
          class Meta:
              model = MyModel
      

      你能用装饰器覆盖初始化吗?此外,在 attrs.update() 之前应该有一个 if 语句,因为我想设置一个默认值而不是覆盖可能已经存在的内容。 ——凯文

      未经测试,但如果你经常使用它,我想你可以从 MyForm 继承。

      【讨论】:

      • 你能用装饰器覆盖初始化吗?此外,在 attrs.update() 之前应该有一个 if 语句,因为我想设置一个默认值而不是覆盖可能已经存在的内容。
      • 我认为装饰器旨在与可调用对象一起使用,重写构造函数应该通过正常的继承机制来完成。在 django 中,有一些函数返回类并不少见,这些函数通常被称为“工厂”。使用“if”条件更新(未经测试)。
      【解决方案5】:

      对于 ModelForm,我们可以使用它。

      from django import forms
      from django.contrib.auth.models import User 
      
      class UserForm(forms.ModelForm):
          def __init__(self, *args, **kwargs):
              super(UserForm, self).__init__(*args, **kwargs)
      
              # change a widget attribute:
              self.fields['user_permissions'].widget.attrs["size"] = 5
              self.fields['user_permissions'].widget.attrs["class"] = 'form-control required'
      
          class Meta:
              model = User 
      

      【讨论】:

        猜你喜欢
        • 2012-04-11
        • 2018-03-25
        • 2017-11-13
        • 2014-12-10
        • 2018-07-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-14
        相关资源
        最近更新 更多