Define css class in django Forms
PythonDjangoDjango FormsPython Problem Overview
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.
Python Solutions
Solution 1 - Python
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.
Solution 2 - Python
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.
Solution 3 - Python
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'
Solution 4 - Python
Use [django-widget-tweaks][1], 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][2] 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][3]'s answer
-
Add django-widget-tweak link
EDIT 2
-
Update filter according to [Bhyd][4]'s comment
[1]: https://github.com/kmike/django-widget-tweaks "django-widget-tweaks" [2]: https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.BoundField [3]: https://stackoverflow.com/users/2369865/dimyg [4]: https://stackoverflow.com/users/2823526/bhyd
Solution 5 - Python
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.
Solution 6 - Python
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.
Solution 7 - Python
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'
}
))
Solution 8 - Python
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'}
Solution 9 - Python
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
Solution 10 - Python
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'
Solution 11 - Python
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})
Solution 12 - Python
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})
Solution 13 - Python
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'),
)
)
Solution 14 - Python
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'}))