Using HTML5 fields with WTForms

Sixhobbits picture Sixhobbits · Jan 10, 2016 · Viewed 6.9k times · Source

I am using Flask to develop a web application. I was originally doing HTML forms manually, and then switched over to using WTForms (this is an educational project, so I am showing each step of building the project).

I got a bit confused when trying to add HTML5 form fields, such as EmailField. I searched the WTForms documentation, and online, and I couldn't find out how to create a WTForm using an HTML5 EmailField.

I then installed this module https://pypi.python.org/pypi/wtforms-html5 which allowed for it, and everything worked. But I was unhappy about adding an extra dependency, especially as it doesn't seem to be actively developed (https://github.com/brutus/wtforms-html5).

I then ended up on the WTForms github page, and found that actually there is support for all the new HTML5 fields, but that these fields aren't imported by default. https://github.com/wtforms/wtforms/blob/master/wtforms/fields/html5.py Therefore instead of using

from WTForms import EmailField

As one would infer from

from WTForms import TextField

One instead has to use

from wtforms.fields.html5 import EmailField

I was previously using the wtforms-html5 module as follows

from wtforms_html5 import EmailField

I therefore changed all occurrences of wtforms_html5 to wtforms.fields.html5 and my application is working exactly as expected.

Ok, thanks for reading all the background. Now for the questions:

  • Why aren't any of the html5 fields (EmailField, DateField, etc) mentioned in the WTForms documentation?

  • Why aren't these fields imported into WTForms by default like the others

  • Are these fields stable/ intended for use?

  • What's best practice for importing fields from WTForms?

For Text field, I can use any of the following:

from wtforms import TextField
from wtforms.fields import TextField
from wtforms.fields.simple import TextField

But for EmailField, I have to use

from wtforms.fields.html5 import EmailField

I would like:

from wtforms.fields import TextField
from wtforms.fields import EmailField

But this would require adding a line to the fields [__init__][1] file, which I am unwilling to do as it is an educational project and this would just confuse the learners.

I am looking for

  • Insight as to why WTForms does not document or by default import the html5 fields
  • Any reason to continue using the wtforms-html5 third-party module.

Answer

Crast picture Crast · Jan 15, 2016

preface, I'm one of the authors and presently the primary maintainer of WTForms

Before I get to the why I should mention a really common pattern for people using WTForms is to create your own module which composes all the bits you want into a single namespace.

For example in myapp/forms.py you do something like:

from wtforms.fields import *
from wtforms import widgets, Form as _Form
from wtforms.fields.html5 import EmailField, 


class Form(_Form):
    """Awesome base form for myapp. Includes CSRF by default"""
    class Meta:
        csrf = True
        csrf_secret = 'secretpasswordhere'

        @property
        def csrf_context(self):
            return get_current_request().session

    # maybe add some methods you really wanted to have on your Form class

You might use the above like:

from myapp.forms import Form, TextField, EmailField, ...

class UserForm(Form):
    name = TextField(...)
    email = EmailField(...)

or alternately with a star import like from myapp.forms import *

You'll note I also included a custom form subclass which sets up CSRF and provides a CSRF context by default, which isn't strictly necessary. (By the way Flask-WTF does similar CSRF setup for you if you're using flask, but the point was to illustrate how you can easily come up with your own integration.)


Now the why.

WTForms' core idea was to come up with a very simple, solid framework that works for the majority of use cases well, but is extensible enough that people can provide companion tools to work with specific use cases.

Early on, the solution to doing that was to incorporate extensions for interop with various libraries. But that posed a problem in that it vastly increased the complexity and the surface area of testing, plus it would drive WTForms releases in odd ways (Django just changed this thing, now you need to release a new WTForms). So in 2015, we made the decision to move all the extensions to their own packages to allow them their own release schedule.

Rather than force people to use a single package that tries to do everything, this has resulted in a really great ecosystem emerging with solid companion packages like Flask-WTF, WTForms-Alchemy and WTForms-Django to name a few.

As to why the HTML5 types aren't documented; well, that's an omission. Also, some history: At some point we switched the default WTForms field output from XHTML-style to HTML compact syntax; but kept the core field outputs. So then we got people contributing back XHTML forms, people contributing html5 fields, and people wishing the default fields used HTML5 types, all after we guaranteed backwards compatibility within a major version, which forced our hand a bit.


I know that's a long answer, and maybe the short way to say it is: While WTForms does generally work with most web frameworks out the box, it is designed to be configured and customized to your uses; not plug and play for everything.