diff --git a/docs/newforms.txt b/docs/newforms.txt
index d72b22f092..aa48d5c162 100644
--- a/docs/newforms.txt
+++ b/docs/newforms.txt
@@ -103,11 +103,63 @@ fields: ``subject``, ``message``, ``sender`` and ``cc_myself``. We'll explain
the different types of fields -- e.g., ``CharField`` and ``EmailField`` --
shortly.
+Creating form instances
+-----------------------
+
+A form instance is either **bound** or **unbound** to a set of data.
+
+ * If it's **bound** to a set of data, it's capable of validating that data
+ and rendering the form as HTML with the data displayed in the HTML.
+
+ * If it's **unbound**, it cannot do validation (because there's no data to
+ validate!), but it can still render the blank form as HTML.
+
+To create an unbound form instance, simply instantiate the class::
+
+ >>> f = ContactForm()
+
+To bind data to a form, pass the data 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)
+
+In this dictionary, the keys are the field names, which correspond to the
+attributes in your ``Form`` class. The values are the data you're trying
+to validate. These will usually be strings, but there's no requirement that
+they be strings; the type of data you pass depends on the ``Field``, as we'll
+see in a moment.
+
+If you need to distinguish between bound and unbound form instances at runtime,
+check the value of the form's ``is_bound`` attribute::
+
+ >>> f = ContactForm()
+ >>> f.is_bound
+ False
+ >>> f = ContactForm({'subject': 'hello'})
+ >>> f.is_bound
+ True
+
+Note that passing an empty dictionary creates a *bound* form with empty data::
+
+ >>> f = ContactForm({})
+ >>> f.is_bound
+ True
+
+If you have a bound ``Form`` instance and want to change the data somehow, or
+if you want to bind an unbound ``Form`` instance to some data, create another
+``Form`` instance. There is no way to change data in a ``Form`` instance. Once
+a ``Form`` instance has been created, you should consider its data immutable,
+whether it has data or not.
+
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::
+The first thing we can do with a form is output it as HTML. To do so, instantiate
+it and ``print`` it.
>>> f = ContactForm()
>>> print f
@@ -116,6 +168,23 @@ it and ``print`` it::
+If the form is bound to data, the HTML output will include that data
+appropriately. For example, if a field is represented by an
+````, the data will be in the ``value`` attribute. If a
+field is represented by an ````, then that HTML will
+include ``checked="checked"`` if appropriate::
+
+ >>> data = {'subject': 'hello',
+ ... 'message': 'Hi there',
+ ... 'sender': 'foo@example.com',
+ ... 'cc_myself': True}
+ >>> f = ContactForm(data)
+ >>> print f
+
+
+
+
+
This default output is a two-column HTML table, with a ``
`` for each field.
Notice the following:
@@ -328,27 +397,21 @@ 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::
+validating data. With a bound ``Form`` instance, call the ``is_valid()``
+method to run validation and return a boolean designating whether the data was
+valid::
>>> 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::
+Let's try with some invalid data. In this case, ``subject`` is blank (an error,
+because all fields are required by default) and ``sender`` is not a valid
+e-mail address::
>>> data = {'subject': '',
... 'message': 'Hi there',
@@ -358,16 +421,89 @@ Let's try with some invalid data::
>>> f.is_valid()
False
-Access the ``Form`` attribute ``errors`` to get a dictionary of error messages,
-keyed by the field name::
+Access the ``Form`` attribute ``errors`` to get a dictionary of error messages::
>>> f.errors
{'sender': [u'Enter a valid e-mail address.'], 'subject': [u'This field is required.']}
+In this dictionary, the keys are the field names, and the values are lists of
+Unicode strings representing the error messages.
+
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``.
+Behavior of unbound forms
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It's meaningless to validate a form with no data, but, for the record, here's
+what happens with unbound forms::
+
+ >>> f = ContactForm()
+ >>> f.is_valid()
+ False
+ >>> f.errors
+ {}
+
+Accessing "clean" data
+----------------------
+
+Each ``Field`` in a ``Form`` class is responsible not only for validating data,
+but also for "cleaning" it -- normalizing it to a consistent format. This is a
+nice feature, because it allows data for a particular field to be input in
+a variety of ways, always resulting in consistent output.
+
+For example, ``DateField`` normalizes input into a Python ``datetime.date``
+object. Regardless of whether you pass it a string in the format
+``'1994-07-15'``, a ``datetime.date`` object or a number of other formats,
+``DateField`` will always normalize it to a ``datetime.date`` object as long as
+it's valid.
+
+Once you've created a ``Form`` instance with a set of data and validated it,
+you can access the clean data via the ``clean_data`` attribute of the ``Form``
+object::
+
+ >>> data = {'subject': 'hello',
+ ... 'message': 'Hi there',
+ ... 'sender': 'foo@example.com',
+ ... 'cc_myself': True}
+ >>> f = ContactForm(data)
+ >>> f.is_valid()
+ True
+ >>> f.clean_data
+ {'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'}
+
+Note that any text-based field -- such as ``CharField`` or ``EmailField`` --
+always cleans the input into a Unicode string. We'll cover the encoding
+implications later in this document.
+
+If your data does *not* validate, your ``Form`` instance will not have a
+``clean_data`` attribute::
+
+ >>> data = {'subject': '',
+ ... 'message': 'Hi there',
+ ... 'sender': 'invalid e-mail address',
+ ... 'cc_myself': True}
+ >>> f = ContactForm(data)
+ >>> f.is_valid()
+ False
+ >>> f.clean_data
+ Traceback (most recent call last):
+ ...
+ AttributeError: 'ContactForm' object has no attribute 'clean_data'
+
+Behavior of unbound forms
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It's meaningless to request "clean" data in a form with no data, but, for the
+record, here's what happens with unbound forms::
+
+ >>> f = ContactForm()
+ >>> f.clean_data
+ Traceback (most recent call last):
+ ...
+ AttributeError: 'ContactForm' object has no attribute 'clean_data'
+
More coming soon
================
@@ -378,9 +514,3 @@ 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
-====================