Define css class in django Forms
Question:
Assume I have a form
class SampleClass(forms.Form):
name = forms.CharField(max_length=30)
age = forms.IntegerField()
django_hacker = forms.BooleanField(required=False)
Is there a way for me to define css classes on each field such that I can then use jQuery based on class in my rendered page?
I was hoping not to have to manually build the form.
Answers:
Answered my own question. Sigh
http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.Widget.attrs
I didn’t realize it was passed into the widget constructor.
Here is another solution for adding class definitions to the widgets after declaring the fields in the class.
def __init__(self, *args, **kwargs):
super(SampleClass, self).__init__(*args, **kwargs)
self.fields['name'].widget.attrs['class'] = 'my_class'
Here is a variation on the above which will give all fields the same class (e.g. jquery nice rounded corners).
# Simple way to assign css class to every field
def __init__(self, *args, **kwargs):
super(TranslatedPageForm, self).__init__(*args, **kwargs)
for myField in self.fields:
self.fields[myField].widget.attrs['class'] = 'ui-state-default ui-corner-all'
Expanding on the method pointed to at docs.djangoproject.com:
class MyForm(forms.Form):
comment = forms.CharField(
widget=forms.TextInput(attrs={'size':'40'}))
I thought it was troublesome to have to know the native widget type for every field, and thought it funny to override the default just to put a class name on a form field. This seems to work for me:
class MyForm(forms.Form):
#This instantiates the field w/ the default widget
comment = forms.CharField()
#We only override the part we care about
comment.widget.attrs['size'] = '40'
This seems a little cleaner to me.
Here is Simple way to alter in view. add below in view just before passing it into template.
form = MyForm(instance = instance.obj)
form.fields['email'].widget.attrs = {'class':'here_class_name'}
Yet another solution that doesn’t require changes in python code and so is better for designers and one-off presentational changes: django-widget-tweaks. Hope somebody will find it useful.
Use django-widget-tweaks, it is easy to use and works pretty well.
Otherwise this can be done using a custom template filter.
Considering you render your form this way :
<form action="/contact/" method="post">
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="id_subject">Email subject:</label>
{{ form.subject }}
</div>
</form>
form.subject is an instance of BoundField which has the as_widget method.
you can create a custom filter “addcss” in “my_app/templatetags/myfilters.py”
from django import template
register = template.Library()
@register.filter(name='addcss')
def addcss(value, arg):
css_classes = value.field.widget.attrs.get('class', '').split(' ')
if css_classes and arg not in css_classes:
css_classes = '%s %s' % (css_classes, arg)
return value.as_widget(attrs={'class': css_classes})
And then apply your filter:
{% load myfilters %}
<form action="/contact/" method="post">
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="id_subject">Email subject:</label>
{{ form.subject|addcss:'MyClass' }}
</div>
</form>
form.subjects will then be rendered with the “MyClass” css class.
Hope this help.
EDIT 1
-
Update filter according to dimyG‘s answer
-
Add django-widget-tweak link
EDIT 2
- Update filter according to Bhyd‘s comment
If you want all the fields in the form to inherit a certain class, you just define a parent class, that inherits from forms.ModelForm
, and then inherit from it
class BaseForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(BaseForm, self).__init__(*args, **kwargs)
for field_name, field in self.fields.items():
field.widget.attrs['class'] = 'someClass'
class WhateverForm(BaseForm):
class Meta:
model = SomeModel
This helped me to add the 'form-control'
class to all of the fields on all of the forms of my application automatically, without adding replication of code.
As it turns out you can do this in form constructor (init function) or after form class was initiated. This is sometimes required if you are not writing your own form and that form is coming from somewhere else –
def some_view(request):
add_css_to_fields = ['list','of','fields']
if request.method == 'POST':
form = SomeForm(request.POST)
if form.is_valid():
return HttpResponseRedirect('/thanks/')
else:
form = SomeForm()
for key in form.fields.keys():
if key in add_css_to_fields:
field = form.fields[key]
css_addition = 'css_addition '
css = field.widget.attrs.get('class', '')
field.widget.attrs['class'] = css_addition + css_classes
return render(request, 'template_name.html', {'form': form})
In case that you want to add a class to a form’s field in a template (not in view.py or form.py) for example in cases that you want to modify 3rd party apps without overriding their views, then a template filter as described in Charlesthk answer is very convenient. But in this answer the template filter overrides any existing classes that the field might has.
I tried to add this as an edit but it was suggested to be written as a new answer.
So, here is a template tag that respects the existing classes of the field:
from django import template
register = template.Library()
@register.filter(name='addclass')
def addclass(field, given_class):
existing_classes = field.field.widget.attrs.get('class', None)
if existing_classes:
if existing_classes.find(given_class) == -1:
# if the given class doesn't exist in the existing classes
classes = existing_classes + ' ' + given_class
else:
classes = existing_classes
else:
classes = given_class
return field.as_widget(attrs={"class": classes})
You could also use Django Crispy Forms, it’s a great tool to define forms in case you’d like to use some CSS framework like Bootstrap or Foundation. And it’s easy to specify classes for your form fields there.
Your form class would like this then:
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Div, Submit, Field
from crispy_forms.bootstrap import FormActions
class SampleClass(forms.Form):
name = forms.CharField(max_length=30)
age = forms.IntegerField()
django_hacker = forms.BooleanField(required=False)
helper = FormHelper()
helper.form_class = 'your-form-class'
helper.layout = Layout(
Field('name', css_class='name-class'),
Field('age', css_class='age-class'),
Field('django_hacker', css-class='hacker-class'),
FormActions(
Submit('save_changes', 'Save changes'),
)
)
Simply add the classes to your form as follows.
class UserLoginForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(
attrs={
'class':'form-control',
'placeholder':'Username'
}
))
password = forms.CharField(widget=forms.PasswordInput(
attrs={
'class':'form-control',
'placeholder':'Password'
}
))
You can try this..
class SampleClass(forms.Form):
name = forms.CharField(max_length=30)
name.widget.attrs.update({'class': 'your-class'})
...
You can see more information in: Django Widgets
You can get styling options for all kinds of input fields here
A widget is Django’s representation of an HTML input element. The widget handles the rendering of the HTML, and the extraction of data from a GET/POST dictionary that corresponds to the widget.
email = forms.EmailField(label='Your email', widget=forms.EmailInput(attrs={'class': 'ui segment teal'}))
If you are using ModelForm and has included the necessary fields with fields property, there is a way to define css classes for them. This worked better than the ‘for loop’ method for me because I wanted different types of css classes for different input fields.
fields = ( 'date', 'title'),
widgets = {'date': forms.DateInput(attrs={'class': 'datepicker'}),
'title': forms.TextInput(attrs={'class': 'title'})}
Or you can also try setting them via the constructor of the Form class
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['date'].widget.attrs.update({'class': 'datepicker'})
self.fields['title'].widget.attrs.update({'class':'title'})
To define css
class in django, simply you can use widgets
in forms.
Example:
class ProcessForm(forms.ModelForm):
class Meta:
model = Processmachine
fields = ['machine_name', 'operation_no', 'process_uploadfile'] #https://docs.djangoproject.com/en/3.0/ref/forms/widgets/
widgets = { 'machine_name': forms.TextInput(attrs={ 'class': 'form-control' }),
'operation_no': forms.TextInput(attrs={ 'class': 'form-control' }),
'process_uploadfile': forms.ClearableFileInput(attrs={ 'class': 'form-control' }),
}
In above form, I have used css
class inside attrs
Assume I have a form
class SampleClass(forms.Form):
name = forms.CharField(max_length=30)
age = forms.IntegerField()
django_hacker = forms.BooleanField(required=False)
Is there a way for me to define css classes on each field such that I can then use jQuery based on class in my rendered page?
I was hoping not to have to manually build the form.
Answered my own question. Sigh
http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.Widget.attrs
I didn’t realize it was passed into the widget constructor.
Here is another solution for adding class definitions to the widgets after declaring the fields in the class.
def __init__(self, *args, **kwargs):
super(SampleClass, self).__init__(*args, **kwargs)
self.fields['name'].widget.attrs['class'] = 'my_class'
Here is a variation on the above which will give all fields the same class (e.g. jquery nice rounded corners).
# Simple way to assign css class to every field
def __init__(self, *args, **kwargs):
super(TranslatedPageForm, self).__init__(*args, **kwargs)
for myField in self.fields:
self.fields[myField].widget.attrs['class'] = 'ui-state-default ui-corner-all'
Expanding on the method pointed to at docs.djangoproject.com:
class MyForm(forms.Form):
comment = forms.CharField(
widget=forms.TextInput(attrs={'size':'40'}))
I thought it was troublesome to have to know the native widget type for every field, and thought it funny to override the default just to put a class name on a form field. This seems to work for me:
class MyForm(forms.Form):
#This instantiates the field w/ the default widget
comment = forms.CharField()
#We only override the part we care about
comment.widget.attrs['size'] = '40'
This seems a little cleaner to me.
Here is Simple way to alter in view. add below in view just before passing it into template.
form = MyForm(instance = instance.obj)
form.fields['email'].widget.attrs = {'class':'here_class_name'}
Yet another solution that doesn’t require changes in python code and so is better for designers and one-off presentational changes: django-widget-tweaks. Hope somebody will find it useful.
Use django-widget-tweaks, it is easy to use and works pretty well.
Otherwise this can be done using a custom template filter.
Considering you render your form this way :
<form action="/contact/" method="post">
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="id_subject">Email subject:</label>
{{ form.subject }}
</div>
</form>
form.subject is an instance of BoundField which has the as_widget method.
you can create a custom filter “addcss” in “my_app/templatetags/myfilters.py”
from django import template
register = template.Library()
@register.filter(name='addcss')
def addcss(value, arg):
css_classes = value.field.widget.attrs.get('class', '').split(' ')
if css_classes and arg not in css_classes:
css_classes = '%s %s' % (css_classes, arg)
return value.as_widget(attrs={'class': css_classes})
And then apply your filter:
{% load myfilters %}
<form action="/contact/" method="post">
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="id_subject">Email subject:</label>
{{ form.subject|addcss:'MyClass' }}
</div>
</form>
form.subjects will then be rendered with the “MyClass” css class.
Hope this help.
EDIT 1
-
Update filter according to dimyG‘s answer
-
Add django-widget-tweak link
EDIT 2
- Update filter according to Bhyd‘s comment
If you want all the fields in the form to inherit a certain class, you just define a parent class, that inherits from forms.ModelForm
, and then inherit from it
class BaseForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(BaseForm, self).__init__(*args, **kwargs)
for field_name, field in self.fields.items():
field.widget.attrs['class'] = 'someClass'
class WhateverForm(BaseForm):
class Meta:
model = SomeModel
This helped me to add the 'form-control'
class to all of the fields on all of the forms of my application automatically, without adding replication of code.
As it turns out you can do this in form constructor (init function) or after form class was initiated. This is sometimes required if you are not writing your own form and that form is coming from somewhere else –
def some_view(request):
add_css_to_fields = ['list','of','fields']
if request.method == 'POST':
form = SomeForm(request.POST)
if form.is_valid():
return HttpResponseRedirect('/thanks/')
else:
form = SomeForm()
for key in form.fields.keys():
if key in add_css_to_fields:
field = form.fields[key]
css_addition = 'css_addition '
css = field.widget.attrs.get('class', '')
field.widget.attrs['class'] = css_addition + css_classes
return render(request, 'template_name.html', {'form': form})
In case that you want to add a class to a form’s field in a template (not in view.py or form.py) for example in cases that you want to modify 3rd party apps without overriding their views, then a template filter as described in Charlesthk answer is very convenient. But in this answer the template filter overrides any existing classes that the field might has.
I tried to add this as an edit but it was suggested to be written as a new answer.
So, here is a template tag that respects the existing classes of the field:
from django import template
register = template.Library()
@register.filter(name='addclass')
def addclass(field, given_class):
existing_classes = field.field.widget.attrs.get('class', None)
if existing_classes:
if existing_classes.find(given_class) == -1:
# if the given class doesn't exist in the existing classes
classes = existing_classes + ' ' + given_class
else:
classes = existing_classes
else:
classes = given_class
return field.as_widget(attrs={"class": classes})
You could also use Django Crispy Forms, it’s a great tool to define forms in case you’d like to use some CSS framework like Bootstrap or Foundation. And it’s easy to specify classes for your form fields there.
Your form class would like this then:
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Div, Submit, Field
from crispy_forms.bootstrap import FormActions
class SampleClass(forms.Form):
name = forms.CharField(max_length=30)
age = forms.IntegerField()
django_hacker = forms.BooleanField(required=False)
helper = FormHelper()
helper.form_class = 'your-form-class'
helper.layout = Layout(
Field('name', css_class='name-class'),
Field('age', css_class='age-class'),
Field('django_hacker', css-class='hacker-class'),
FormActions(
Submit('save_changes', 'Save changes'),
)
)
Simply add the classes to your form as follows.
class UserLoginForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(
attrs={
'class':'form-control',
'placeholder':'Username'
}
))
password = forms.CharField(widget=forms.PasswordInput(
attrs={
'class':'form-control',
'placeholder':'Password'
}
))
You can try this..
class SampleClass(forms.Form):
name = forms.CharField(max_length=30)
name.widget.attrs.update({'class': 'your-class'})
...
You can see more information in: Django Widgets
You can get styling options for all kinds of input fields here
A widget is Django’s representation of an HTML input element. The widget handles the rendering of the HTML, and the extraction of data from a GET/POST dictionary that corresponds to the widget.
email = forms.EmailField(label='Your email', widget=forms.EmailInput(attrs={'class': 'ui segment teal'}))
If you are using ModelForm and has included the necessary fields with fields property, there is a way to define css classes for them. This worked better than the ‘for loop’ method for me because I wanted different types of css classes for different input fields.
fields = ( 'date', 'title'),
widgets = {'date': forms.DateInput(attrs={'class': 'datepicker'}),
'title': forms.TextInput(attrs={'class': 'title'})}
Or you can also try setting them via the constructor of the Form class
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['date'].widget.attrs.update({'class': 'datepicker'})
self.fields['title'].widget.attrs.update({'class':'title'})
To define css
class in django, simply you can use widgets
in forms.
Example:
class ProcessForm(forms.ModelForm):
class Meta:
model = Processmachine
fields = ['machine_name', 'operation_no', 'process_uploadfile'] #https://docs.djangoproject.com/en/3.0/ref/forms/widgets/
widgets = { 'machine_name': forms.TextInput(attrs={ 'class': 'form-control' }),
'operation_no': forms.TextInput(attrs={ 'class': 'form-control' }),
'process_uploadfile': forms.ClearableFileInput(attrs={ 'class': 'form-control' }),
}
In above form, I have used css
class inside attrs