[Fixed]-How do I set default widget attributes for a Django ModelForm?

17👍

You can override the constructor in order to modify all TextInput widgets:

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

can you override init with a decorator? also, there should be an if statement before the attrs.update() becuase I want to set a default rather than override what may already be there. – Kevin

Untested, but I guess you can just inherit from MyForm if you use this a lot.

3👍

Create a new widget with your CSS class:

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

In your form use your new widget in all your fields:

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

3👍

One thing I’ve done in the past is create a lambda function that returns the fields I use often:

from django import forms

fancy = lambda: forms.TextInput(attrs={'class': 'derp'})

class MyForm(forms.Form):
    attr1 = fancy()
    attr2 = fancy()
    attr3 = fancy()

I don’t remember why exactly I opted to use a function to handle my situation, but I suspect that it had something to do with creating separate instances of the forms.TextInput object for each form field….

3👍

For ModelForm we can use this.

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 

1👍

You can use following:

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

Now, every time you want to use default attrs for some widget, you just need to create class that inherits from DefaultAttrForm or DefaultAttrModelForm and overwrite method get_default_attrs. Example for normal Django Form:

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

For Model form use following:

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

0👍

You can use this pattern to set the widget in the Django ModelForm.

class UserInfoForm(ModelForm):
    class Meta:
        model = User
        fields = ['name', 'email']
        widgets = {
            'name': TextInput(attrs={
                'class': "form-control",
                'style': 'max-width: 300px;',
                'placeholder': 'Name'
                }),
            'email': EmailInput(attrs={
                'class': "form-control", 
                'style': 'max-width: 300px;',
                'placeholder': 'Email'
                })
        }

Leave a comment