Add attributes (css-class) to formfield

1,405 views
Skip to first unread message

Andreas Pfrengle

unread,
Jul 13, 2011, 1:41:18 PM7/13/11
to Django users
Hello,

I know about assigning attributes to widgets, like shown here:
<https://docs.djangoproject.com/en/1.3/ref/forms/widgets/#customizing-
widget-instances>
or here:
<http://stackoverflow.com/questions/401025/define-css-class-in-django-
forms>

However, I want to assign an additional attribute to a formfield,
since we want a css class for a div that is wrapped around the
presentation of a field. I've tried to assign an attribute in the
form's __init__, like:

self.fields['my_field'].div_css = "test"

If I try to fetch it in the template however, it resolves to an empty
string (supposedly the attribute doesn't exist):
{% for field in form.visible_fields %}
<div class="{{ field.div_css }}" >
....
</div>
{% endfor %}

Any help or explanation what goes on inside Django is appreciated.

Regards,
Andreas

Shawn Milochik

unread,
Jul 13, 2011, 1:47:45 PM7/13/11
to django...@googlegroups.com

Following this as a sample (from the docs you linked to):
widget=forms.TextInput(attrs={'class':'special'}))

You'd do this:
widget=forms.TextInput(attrs={'div_css':'test'}))

Or, to not clobber other things set in the form, you could do it in the
__init__:

#working example I just did in one of my projects to prove it works
self.fields['release_date'].widget.attrs["div_css"] = 'test'

Andreas Pfrengle

unread,
Jul 13, 2011, 2:00:15 PM7/13/11
to Django users
Hello Shawn,

thanks for your answer, however that's not exactly what I wanted. Now
the html renders to:
<label for="id_n_properties">No. of properties</label>
<input value="4" type="text" name="n_properties" div_css="test"
id="id_n_properties" />

However, I would want:
<div class="test">
<label for="id_n_properties">No. of properties</label>
<input value="4" type="text" name="n_properties"
id="id_n_properties" />
</div>

Additionally, I can't access {{ field.widget.attrs.div_css }} to get
the class directly, I get an empty string instead.

Andre Terra

unread,
Jul 13, 2011, 2:05:06 PM7/13/11
to django...@googlegroups.com
Write a wrapper function and make it even shorter (ok, go ahead and call it syntax sugar):

def css(field, **kwargs):
    field.attrs.update(**kwargs)

use as:

css(self.fields['release_date'], div_css="test")

DISCLAIMER: not tested on a real Field, but I tested it on a simple class in a python shell and it seemed to work

I'll leave it as homework for you to make this a class method and make the syntax even shorter. Maybe even propose a patch!


Cheers,
André Terra / airstrike




--
You received this message because you are subscribed to the Google Groups "Django users" group.
To post to this group, send email to django...@googlegroups.com.
To unsubscribe from this group, send email to django-users+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.


Shawn Milochik

unread,
Jul 13, 2011, 2:25:02 PM7/13/11
to django...@googlegroups.com

Replace 'div_css' in my example with 'class' and you'll get
'class="test"' in your output.


Andre Terra

unread,
Jul 13, 2011, 2:28:37 PM7/13/11
to django...@googlegroups.com
Shawn,

He wants the form attribute to be applied to the div, not the field.


Andreas,

You can't pass an attribute to a field and expect it to show up in a different object altogether. I assume your div isn't handled by django, so you need to fix that first in order to be able to pass extra attributes to it.

A few solutions:
1) Use a fieldset (like the admin does) and then define how *that* gets rendered - complex, flexible.
2) Pass a css attribute to the view (not sure where you're going to get that css_class stuff from) and use it in your template's context, then add classes on the fly during template compilation - easy, ugly.



Cheers,
André


Andreas Pfrengle

unread,
Jul 13, 2011, 6:18:24 PM7/13/11
to Django users
Hello Andre,

it took me some time, but since I couldn't get insight in suggestion
1) and 2) really seemed too ugly, I've discovered an intermediate
solution.
I came around it when trying to make suggestion 2) a little less ugly,
and after all it's still quite easy ;-)

3) Write a template-filter that looks for a css-attribute in the
field, which I set dynamically during the form's __init__.
I also understand now why my first approach didn't work after
realising how BoundFields are created by Django.

I've put my solution here:
<http://djangosnippets.org/snippets/2487/>

Tom Evans

unread,
Jul 14, 2011, 5:25:11 AM7/14/11
to django...@googlegroups.com


All these replies, and none of them have mentioned why your original
approach doesn't work.

When iterating through a form in your template, each field instance
returned is not a field from form.fields, it is a BoundField that
represents the corresponding field from form.fields.

The original field object is available in bfield.field . Therefore,
with your original code, you can do this in the template:

   {% for bfield in form.visible_fields %}
       <div class="{{ bfield.field.div_css }}" >


       ....
       </div>
   {% endfor %}

Cheers

Tom

Andreas Pfrengle

unread,
Jul 15, 2011, 2:44:10 PM7/15/11
to Django users
Tom,

it's really so easy, thank you!
Seems now I've learned the hard way how forms and fields are
working ;-)

Andreas
Reply all
Reply to author
Forward
0 new messages