Wtforms, add a class to a form dynamically
Asked Answered
G

4

22

is there a way i could send a form's (css) class from python? For example:

class Company(Form):
    companyName = TextField('Company Name', [validators.Length(min=3, max = 60)])

This renders a simple text field, but i want that text field to have the css class of .companyName, is that possible directly from python?

I know that i can put a id="companyName" directly from python, but not class.

Help.

Update: I tried class_="companyName" and it did not work, i got:

__init__() got an unexpected keyword argument '_class'
Glenoid answered 3/7, 2012 at 11:16 Comment(0)
S
28

WTForms does not allow you to set display options (such as class name) in the field initialization. However, there are several ways to get around this:

  1. If all of your fields should include a class name as well as an ID then just pass in each field's short_name to it when you render it:

    <dl>
    {% for field in form %}
    <dt>{{field.label}}</dt>
    <dd>{{field(class_=field.short_name)}}</dd>
    {% endfor %}
    </dl>
    
  2. Create a custom widget mixin that provides the class name:

    from wtforms.fields import StringField
    from wtforms.widgets import TextInput
    
    class ClassedWidgetMixin(object):
        """Adds the field's name as a class 
        when subclassed with any WTForms Field type.
    
        Has not been tested - may not work."""
        def __init__(self, *args, **kwargs):
            super(ClassedWidgetMixin, self).__init__(*args, **kwargs)
    
        def __call__(self, field, **kwargs):
            c = kwargs.pop('class', '') or kwargs.pop('class_', '')
            kwargs['class'] = u'%s %s' % (field.short_name, c)
            return super(ClassedWidgetMixin, self).__call__(field, **kwargs)
    
    # An example
    class ClassedTextInput(ClassedWidgetMixin, TextInput):
        pass
    
    class Company(Form):
        company_name = StringField('Company Name', widget=ClassedTextInput)
    
Stacked answered 4/7, 2012 at 14:59 Comment(0)
P
55

Alternatively you can add the class in your template like this for jinja2:

{{ form.name(size=20, class_='input-small') }}
Pommard answered 28/9, 2012 at 15:48 Comment(4)
Saved me as well :) This is a wonderful solution, not sure why an example along these lines isn't somewhere in the WTForm docsPhoenician
I'd vote up ten times if it is possible, this is a much better solution. Now I can sit back and watch WTForms rock~~~Ramin
Although the underscore after class doesn't seem to be necessaryRamin
This solution is much better than the one chosen as the correct answer.Burch
S
28

WTForms does not allow you to set display options (such as class name) in the field initialization. However, there are several ways to get around this:

  1. If all of your fields should include a class name as well as an ID then just pass in each field's short_name to it when you render it:

    <dl>
    {% for field in form %}
    <dt>{{field.label}}</dt>
    <dd>{{field(class_=field.short_name)}}</dd>
    {% endfor %}
    </dl>
    
  2. Create a custom widget mixin that provides the class name:

    from wtforms.fields import StringField
    from wtforms.widgets import TextInput
    
    class ClassedWidgetMixin(object):
        """Adds the field's name as a class 
        when subclassed with any WTForms Field type.
    
        Has not been tested - may not work."""
        def __init__(self, *args, **kwargs):
            super(ClassedWidgetMixin, self).__init__(*args, **kwargs)
    
        def __call__(self, field, **kwargs):
            c = kwargs.pop('class', '') or kwargs.pop('class_', '')
            kwargs['class'] = u'%s %s' % (field.short_name, c)
            return super(ClassedWidgetMixin, self).__call__(field, **kwargs)
    
    # An example
    class ClassedTextInput(ClassedWidgetMixin, TextInput):
        pass
    
    class Company(Form):
        company_name = StringField('Company Name', widget=ClassedTextInput)
    
Stacked answered 4/7, 2012 at 14:59 Comment(0)
T
12

Use render_kw if using WTForms >= 2.1 :

submit = SubmitField(u'Block Submit Buttom', render_kw={"class": "btn btn-primary btn-block"})
Thebault answered 26/5, 2016 at 11:20 Comment(3)
It works for me many days age, but it just failed now. I don't remember what I did then, but almost just like your answer. After Ctrl+F5, the submit button also shows it class btn btn-default:-(... Any possible errors? WTForms==2.1 and Flask-WTF==0.14.2Cincinnati
It's perfectly what I need when I use parsley js for email validate.Mahratta
It look great, it should work but I have the same problem: WTForms is inserting btn-default class; don't work for some reason. Any clues?Chocolate
J
0

In your template, try it

{{ form.companyName( **{'class': 'companyName'} ) }}
Jigger answered 26/2, 2015 at 7:26 Comment(1)
In Python functions you can't use "class" as a named argument because it's a language keyword. For example, myfunc(class='xyz') results in a SyntaxError. Using the myfunc(**{'class': 'xyz'}) like shown above gets around that problem. Thanks for your example!Screeching

© 2022 - 2024 — McMap. All rights reserved.