387 lines
19 KiB
Plaintext
387 lines
19 KiB
Plaintext
====================
|
|
The newforms library
|
|
====================
|
|
|
|
``django.newforms`` is a new replacement for ``django.forms``, the old Django
|
|
form/manipulator/validation framework. This document explains how to use this
|
|
new form library.
|
|
|
|
Migration plan
|
|
==============
|
|
|
|
``django.newforms`` currently is only available in the Django development version
|
|
-- i.e., it's not available in the Django 0.95 release. For the next Django
|
|
release, our plan is to do the following:
|
|
|
|
* As of revision [4208], we've copied the current ``django.forms`` to
|
|
``django.oldforms``. This allows you to upgrade your code *now* rather
|
|
than waiting for the backwards-incompatible change and rushing to fix
|
|
your code after the fact. Just change your import statements like this::
|
|
|
|
from django import forms # old
|
|
from django import oldforms as forms # new
|
|
|
|
* At an undecided future date, we will move the current ``django.newforms``
|
|
to ``django.forms``. This will be a backwards-incompatible change, and
|
|
anybody who is still using the old version of ``django.forms`` at that
|
|
time will need to change their import statements, as described in the
|
|
previous bullet.
|
|
|
|
* We will remove ``django.oldforms`` in the release *after* the next Django
|
|
release -- the release that comes after the release in which we're
|
|
creating the new ``django.forms``.
|
|
|
|
With this in mind, we recommend you use the following import statement when
|
|
using ``django.newforms``::
|
|
|
|
from django import newforms as forms
|
|
|
|
This way, your code can refer to the ``forms`` module, and when
|
|
``django.newforms`` is renamed to ``django.forms``, you'll only have to change
|
|
your ``import`` statements.
|
|
|
|
If you prefer "``import *``" syntax, you can do the following::
|
|
|
|
from django.newforms import *
|
|
|
|
This will import all fields, widgets, form classes and other various utilities
|
|
into your local namespace. Some people find this convenient; others find it
|
|
too messy. The choice is yours.
|
|
|
|
Overview
|
|
========
|
|
|
|
As the ``django.forms`` ("manipulators") system before it, ``django.newforms``
|
|
is intended to handle HTML form display, validation and redisplay. It's what
|
|
you use if you want to perform server-side validation for an HTML form.
|
|
|
|
For example, if your Web site has a contact form that visitors can use to
|
|
send you e-mail, you'd use this library to implement the display of the HTML
|
|
form fields, along with the form validation. Any time you need to use an HTML
|
|
``<form>``, you can use this library.
|
|
|
|
The library deals with these concepts:
|
|
|
|
* **Widget** -- A class that corresponds to an HTML form widget, e.g.
|
|
``<input type="text">`` or ``<textarea>``. This handles rendering of the
|
|
widget as HTML.
|
|
|
|
* **Field** -- A class that is responsible for doing validation, e.g.
|
|
an ``EmailField`` that makes sure its data is a valid e-mail address.
|
|
|
|
* **Form** -- A collection of fields that knows how to validate itself and
|
|
display itself as HTML.
|
|
|
|
The library is decoupled from the other Django components, such as the database
|
|
layer, views and templates. It relies only on Django settings, a couple of
|
|
``django.utils`` helper functions and Django's internationalization hooks (but
|
|
you're not required to be using internationalization features to use this
|
|
library).
|
|
|
|
Form objects
|
|
============
|
|
|
|
The primary way of using the ``newforms`` library is to create a form object.
|
|
Do this by subclassing ``django.newforms.Form`` and specifying the form's
|
|
fields, in a declarative style that you'll be familiar with if you've used
|
|
Django database models. In this section, we'll iteratively develop a form
|
|
object that you might to implement "contact me" functionality on your personal
|
|
Web site.
|
|
|
|
Start with this basic ``Form`` subclass, which we'll call ``ContactForm``::
|
|
|
|
from django import newforms as forms
|
|
|
|
class ContactForm(forms.Form):
|
|
subject = forms.CharField(max_length=100)
|
|
message = forms.CharField()
|
|
sender = forms.EmailField()
|
|
cc_myself = forms.BooleanField()
|
|
|
|
A form is composed of ``Field`` objects. In this case, our form has four
|
|
fields: ``subject``, ``message``, ``sender`` and ``cc_myself``. We'll explain
|
|
the different types of fields -- e.g., ``CharField`` and ``EmailField`` --
|
|
shortly.
|
|
|
|
Outputting forms as HTML
|
|
------------------------
|
|
|
|
The first thing we can do with this is output it as HTML. To do so, instantiate
|
|
it and ``print`` it::
|
|
|
|
>>> f = ContactForm()
|
|
>>> print f
|
|
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>
|
|
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>
|
|
<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>
|
|
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>
|
|
|
|
This default output is a two-column HTML table, with a ``<tr>`` for each field.
|
|
Notice the following:
|
|
|
|
* For flexibility, the output does *not* include the ``<table>`` and
|
|
``</table>`` tags, nor does it include the ``<form>`` and ``</form>``
|
|
tags or an ``<input type="submit">`` tag. It's your job to do that.
|
|
|
|
* Each field type has a default HTML representation. ``CharField`` and
|
|
``EmailField`` are represented by an ``<input type="text">``.
|
|
``BooleanField`` is represented by an ``<input type="checkbox">``. Note
|
|
these are merely sensible defaults; you can specify which HTML to use for
|
|
a given field by using ``widgets``, which we'll explain shortly.
|
|
|
|
* The HTML ``name`` for each tag is taken directly from its attribute name
|
|
in the ``ContactForm`` class.
|
|
|
|
* The text label for each field -- e.g. ``'Subject:'``, ``'Message:'`` and
|
|
``'CC myself:'`` is generated from the field name by converting all
|
|
underscores to spaces and upper-casing the first letter. Again, note
|
|
these are merely sensible defaults; you can also specify labels manually.
|
|
|
|
* Each text label is surrounded in an HTML ``<label>`` tag, which points
|
|
to the appropriate form field via its ``id``. Its ``id``, in turn, is
|
|
generated by prepending ``'id_'`` to the field name. The ``id``
|
|
attributes and ``<label>`` tags are included in the output by default, to
|
|
follow best practices, but you can change that behavior.
|
|
|
|
Although ``<table>`` output is the default output style when you ``print`` a
|
|
form, other output styles are available. Each style is available as a method on
|
|
a form object, and each rendering method returns a Unicode object.
|
|
|
|
``as_p()``
|
|
~~~~~~~~~~
|
|
|
|
``Form.as_p()`` renders the form as a series of ``<p>`` tags, with each ``<p>``
|
|
containing one field::
|
|
|
|
>>> f = ContactForm()
|
|
>>> f.as_p()
|
|
u'<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></p>\n<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>'
|
|
>>> print f.as_p()
|
|
<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p>
|
|
<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>
|
|
<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></p>
|
|
<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
|
|
|
|
``as_ul()``
|
|
~~~~~~~~~~~
|
|
|
|
``Form.as_ul()`` renders the form as a series of ``<li>`` tags, with each
|
|
``<li>`` containing one field. It does *not* include the ``<ul>`` or ``</ul>``,
|
|
so that you can specify any HTML attributes on the ``<ul>`` for flexibility::
|
|
|
|
>>> f = ContactForm()
|
|
>>> f.as_ul()
|
|
u'<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>\n<li><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li>'
|
|
>>> print f.as_ul()
|
|
<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li>
|
|
<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>
|
|
<li><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></li>
|
|
<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li>
|
|
|
|
``as_table()``
|
|
~~~~~~~~~~~~~~
|
|
|
|
Finally, ``Form.as_table()`` outputs the form as an HTML ``<table>``. This is
|
|
exactly the same as ``print``. In fact, when you ``print`` a form object, it
|
|
calls its ``as_table()`` method behind the scenes::
|
|
|
|
>>> f = ContactForm()
|
|
>>> f.as_table()
|
|
u'<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>'
|
|
>>> print f.as_table()
|
|
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>
|
|
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>
|
|
<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>
|
|
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>
|
|
|
|
Configuring HTML ``<label>`` tags
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
An HTML ``<label>`` tag designates which label text is associated with which
|
|
form element. This small enhancement makes forms more usable and more accessible
|
|
to assistive devices. It's always a good idea to use ``<label>`` tags.
|
|
|
|
By default, the form rendering methods include HTML ``id`` attributes on the
|
|
form elements and corresponding ``<label>`` tags around the labels. The ``id``
|
|
attribute values are generated by prepending ``id_`` to the form field names.
|
|
This behavior is configurable, though, if you want to change the ``id``
|
|
convention or remove HTML ``id`` attributes and ``<label>`` tags entirely.
|
|
|
|
Use the ``auto_id`` argument to the ``Form`` constructor to control the label
|
|
and ``id`` behavior. This argument must be ``True``, ``False`` or a string.
|
|
|
|
If ``auto_id`` is ``False``, then the form output will not include ``<label>``
|
|
tags nor ``id`` attributes::
|
|
|
|
>>> f = ContactForm(auto_id=False)
|
|
>>> print f.as_table()
|
|
<tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" /></td></tr>
|
|
<tr><th>Message:</th><td><input type="text" name="message" /></td></tr>
|
|
<tr><th>Sender:</th><td><input type="text" name="sender" /></td></tr>
|
|
<tr><th>Cc myself:</th><td><input type="checkbox" name="cc_myself" /></td></tr>
|
|
>>> print f.as_ul()
|
|
<li>Subject: <input type="text" name="subject" maxlength="100" /></li>
|
|
<li>Message: <input type="text" name="message" /></li>
|
|
<li>Sender: <input type="text" name="sender" /></li>
|
|
<li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
|
|
>>> print f.as_p()
|
|
<p>Subject: <input type="text" name="subject" maxlength="100" /></p>
|
|
<p>Message: <input type="text" name="message" /></p>
|
|
<p>Sender: <input type="text" name="sender" /></p>
|
|
<p>Cc myself: <input type="checkbox" name="cc_myself" /></p>
|
|
|
|
If ``auto_id`` is set to ``True``, then the form output *will* include
|
|
``<label>`` tags and will simply use the field name as its ``id`` for each form
|
|
field::
|
|
|
|
>>> f = ContactForm(auto_id=True)
|
|
>>> print f.as_table()
|
|
<tr><th><label for="subject">Subject:</label></th><td><input id="subject" type="text" name="subject" maxlength="100" /></td></tr>
|
|
<tr><th><label for="message">Message:</label></th><td><input type="text" name="message" id="message" /></td></tr>
|
|
<tr><th><label for="sender">Sender:</label></th><td><input type="text" name="sender" id="sender" /></td></tr>
|
|
<tr><th><label for="cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="cc_myself" /></td></tr>
|
|
>>> print f.as_ul()
|
|
<li><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" /></li>
|
|
<li><label for="message">Message:</label> <input type="text" name="message" id="message" /></li>
|
|
<li><label for="sender">Sender:</label> <input type="text" name="sender" id="sender" /></li>
|
|
<li><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself" /></li>
|
|
>>> print f.as_p()
|
|
<p><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" /></p>
|
|
<p><label for="message">Message:</label> <input type="text" name="message" id="message" /></p>
|
|
<p><label for="sender">Sender:</label> <input type="text" name="sender" id="sender" /></p>
|
|
<p><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself" /></p>
|
|
|
|
If ``auto_id`` is set to a string containing the format character ``'%s'``,
|
|
then the form output will include ``<label>`` tags, and will generate ``id``
|
|
attributes based on the format string. For example, for a format string
|
|
``'field_%s'``, a field named ``subject`` will get the ``id``
|
|
``'field_subject'``. Continuing our example::
|
|
|
|
>>> f = ContactForm(auto_id='id_for_%s')
|
|
>>> print f.as_table()
|
|
<tr><th><label for="id_for_subject">Subject:</label></th><td><input id="id_for_subject" type="text" name="subject" maxlength="100" /></td></tr>
|
|
<tr><th><label for="id_for_message">Message:</label></th><td><input type="text" name="message" id="id_for_message" /></td></tr>
|
|
<tr><th><label for="id_for_sender">Sender:</label></th><td><input type="text" name="sender" id="id_for_sender" /></td></tr>
|
|
<tr><th><label for="id_for_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></td></tr>
|
|
>>> print f.as_ul()
|
|
<li><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li>
|
|
<li><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></li>
|
|
<li><label for="id_for_sender">Sender:</label> <input type="text" name="sender" id="id_for_sender" /></li>
|
|
<li><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li>
|
|
>>> print f.as_p()
|
|
<p><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></p>
|
|
<p><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></p>
|
|
<p><label for="id_for_sender">Sender:</label> <input type="text" name="sender" id="id_for_sender" /></p>
|
|
<p><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></p>
|
|
|
|
If ``auto_id`` is set to any other true value -- such as a string that doesn't
|
|
include ``%s`` -- then the library will act as if ``auto_id`` is ``True``.
|
|
|
|
By default, ``auto_id`` is set to the string ``'id_%s'``.
|
|
|
|
Notes on field ordering
|
|
~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
In the ``as_p()``, ``as_ul()`` and ``as_table()`` shortcuts, the fields are
|
|
displayed in the order in which you define them in your form class. For
|
|
example, in the ``ContactForm`` example, the fields are defined in the order
|
|
``subject``, ``message``, ``sender``, ``cc_myself``. To reorder the HTML
|
|
output, just change the order in which those fields are listed in the class.
|
|
|
|
More granular output
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The ``as_p()``, ``as_ul()`` and ``as_table()`` methods are simply shortcuts for
|
|
lazy developers -- they're not the only way a form object can be displayed.
|
|
|
|
To display the HTML for a single field in your form, use dictionary lookup
|
|
syntax using the field's name as the key, and print the resulting object::
|
|
|
|
>>> f = ContactForm()
|
|
>>> print f['subject']
|
|
<input id="id_subject" type="text" name="subject" maxlength="100" />
|
|
>>> print f['message']
|
|
<input type="text" name="message" id="id_message" />
|
|
>>> print f['sender']
|
|
<input type="text" name="sender" id="id_sender" />
|
|
>>> print f['cc_myself']
|
|
<input type="checkbox" name="cc_myself" id="id_cc_myself" />
|
|
|
|
Call ``str()`` or ``unicode()`` on the field to get its rendered HTML as a
|
|
string or Unicode object, respectively::
|
|
|
|
>>> str(f['subject'])
|
|
'<input id="id_subject" type="text" name="subject" maxlength="100" />'
|
|
>>> unicode(f['subject'])
|
|
u'<input id="id_subject" type="text" name="subject" maxlength="100" />'
|
|
|
|
The field-specific output honors the form object's ``auto_id`` setting::
|
|
|
|
>>> f = ContactForm(auto_id=False)
|
|
>>> print f['message']
|
|
<input type="text" name="message" />
|
|
>>> f = ContactForm(auto_id='id_%s')
|
|
>>> print f['message']
|
|
<input type="text" name="message" id="id_message" />
|
|
|
|
Using forms to validate data
|
|
----------------------------
|
|
|
|
In addition to HTML form display, a ``Form`` class is responsible for
|
|
validating data. To validate data, pass it as a dictionary as the first
|
|
parameter to your ``Form`` class' constructor::
|
|
|
|
>>> data = {'subject': 'hello',
|
|
... 'message': 'Hi there',
|
|
... 'sender': 'foo@example.com',
|
|
... 'cc_myself': True}
|
|
>>> f = ContactForm(data)
|
|
|
|
From then on, the ``Form`` instance is bound to that data. If you want to
|
|
change the data somehow, or validate other data, create another ``Form``
|
|
instance.
|
|
|
|
Once you have a ``Form`` instance that's bound to data, call the ``is_valid()``
|
|
method to run validation and return a boolean designating whether the data was
|
|
valid::
|
|
|
|
>>> f.is_valid()
|
|
True
|
|
|
|
Let's try with some invalid data::
|
|
|
|
>>> data = {'subject': '',
|
|
... 'message': 'Hi there',
|
|
... 'sender': 'invalid e-mail address',
|
|
... 'cc_myself': True}
|
|
>>> f = ContactForm(data)
|
|
>>> f.is_valid()
|
|
False
|
|
|
|
Access the ``Form`` attribute ``errors`` to get a dictionary of error messages,
|
|
keyed by the field name::
|
|
|
|
>>> f.errors
|
|
{'sender': [u'Enter a valid e-mail address.'], 'subject': [u'This field is required.']}
|
|
|
|
You can access ``errors`` without having to call ``is_valid()`` first. The
|
|
form's data will be validated the first time either you call ``is_valid()`` or
|
|
access ``errors``.
|
|
|
|
More coming soon
|
|
================
|
|
|
|
That's all the documentation for now. For more, see the file
|
|
http://code.djangoproject.com/browser/django/trunk/tests/regressiontests/forms/tests.py
|
|
-- the unit tests for ``django.newforms``. This can give you a good idea of
|
|
what's possible.
|
|
|
|
If you're really itching to learn and use this library, please be patient.
|
|
We're working hard on finishing both the code and documentation.
|
|
|
|
Using forms with templates
|
|
==========================
|
|
|
|
Using forms in views
|
|
====================
|