Index: docs/forms.txt
===================================================================
--- docs/forms.txt	(revision 2750)
+++ docs/forms.txt	(working copy)
@@ -16,7 +16,9 @@
 
 We'll take a top-down approach to examining Django's form validation framework,
 because much of the time you won't need to use the lower-level APIs. Throughout
-this document, we'll be working with the following model, a "place" object::
+this document, we'll be working with the following model, a "place" object
+(that resides in the ``myproject/testapp`` directory if we ever need to
+import it)::
 
     PLACE_TYPES = (
         (1, 'Bar'),
@@ -53,11 +55,11 @@
 the later modifies existing instances.  Both types of classes are automatically
 created when you define a new class::
 
-    >>> from django.models.places import places
-    >>> places.AddManipulator
-    <class django.models.places.PlaceManipulatorAdd at 0x4c1540>
-    >>> places.ChangeManipulator
-    <class django.models.places.PlaceManipulatorChange at 0x4c1630>
+    >>> from myproject.testapp import Place
+    >>> Place.AddManipulator
+    <class 'django.models.manipulators.AddManipulator'>
+    >>> Place.ChangeManipulator
+    <class 'django.models.manipulators.ChangeManipulator'>
 
 Using the ``AddManipulator``
 ----------------------------
@@ -67,13 +69,13 @@
 
     from django.shortcuts import render_to_response
     from django.http import Http404, HttpResponse, HttpResponseRedirect
-    from django.models.places import places
     from django import forms
+    from myproject.testapp import Place
 
     def naive_create_place(request):
         """A naive approach to creating places; don't actually use this!"""
         # Create the AddManipulator.
-        manipulator = places.AddManipulator()
+        manipulator = Place.AddManipulator()
 
         # Make a copy of the POSTed data so that do_html2python can
         # modify it in place (request.POST is immutable).
@@ -109,8 +111,8 @@
         """Simplistic place form view; don't actually use anything like this!"""
         # Create a FormWrapper object that the template can use. Ignore
         # the last two arguments to FormWrapper for now.
-        form = forms.FormWrapper(places.AddManipulator(), {}, {})
-        return render_to_response('places/naive_create_form.html', {'form': form})
+        form = forms.FormWrapper(Place.AddManipulator(), {}, {})
+        return render_to_response('testapp/naive_create_form.html', {'form': form})
 
 (This view, as well as all the following ones, has the same imports as in the
 first example above.)
@@ -155,16 +157,16 @@
 creation view that takes validation into account::
 
     def create_place_with_validation(request):
-        manipulator = places.AddManipulator()
+        manipulator = Place.AddManipulator()
         new_data = request.POST.copy()
 
         # Check for validation errors
         errors = manipulator.get_validation_errors(new_data)
         if errors:
-            return render_to_response('places/errors.html', {'errors': errors})
+            return render_to_response('testapp/errors.html', {'errors': errors})
         else:
-            manipulator.do_html2python(request.POST)
-            new_place = manipulator.save(request.POST)
+            manipulator.do_html2python(new_data)
+            new_place = manipulator.save(new_data)
             return HttpResponse("Place created: %s" % new_place)
 
 In this new version, errors will be found -- ``manipulator.get_validation_errors``
@@ -199,7 +201,7 @@
 both be available on the same page, so errors with fields can be presented in
 context.
 
-.. admonition:: Philosophy::
+.. admonition:: Philosophy:
 
     Finally, for the HTTP purists in the audience (and the authorship), this
     nicely matches the "true" meanings of HTTP GET and HTTP POST: GET fetches
@@ -208,7 +210,7 @@
 Below is the finished view::
 
     def create_place(request):
-        manipulator = places.AddManipulator()
+        manipulator = Place.AddManipulator()
 
         if request.POST:
             # If data was POSTed, we're trying to create a new Place.
@@ -233,7 +235,7 @@
 
         # Create the FormWrapper, template, context, response.
         form = forms.FormWrapper(manipulator, new_data, errors)
-        return render_to_response('places/create_form.html', {'form': form})
+        return render_to_response('testapp/create_form.html', {'form': form})
 
 and here's the ``create_form`` template::
 
@@ -300,7 +302,7 @@
         # Get the place in question from the database and create a
         # ChangeManipulator at the same time.
         try:
-            manipulator = places.ChangeManipulator(place_id)
+            manipulator = Place.ChangeManipulator(place_id)
         except places.PlaceDoesNotExist:
             raise Http404
 
@@ -322,7 +324,7 @@
             new_data = place.__dict__
 
         form = forms.FormWrapper(manipulator, new_data, errors)
-        return render_to_response('places/edit_form.html', {'form': form, 'place': place})
+        return render_to_response('testapp/edit_form.html', {'form': form, 'place': place})
 
 The only real differences are:
 
@@ -409,8 +411,8 @@
 One useful feature of manipulators is the automatic validation. Validation is
 done using a simple validation API: A validator is a callable that raises a
 ``ValidationError`` if there's something wrong with the data.
-``django.core.validators`` defines a host of validator functions, but defining
-your own couldn't be easier::
+``django.core.validators`` defines a host of validator functions (see below),
+but defining your own couldn't be easier::
 
     from django.core import validators
     from django import forms
@@ -432,10 +434,154 @@
 
 The arguments to a validator function take a little explanation.  ``field_data``
 is the value of the field in question, and ``all_data`` is a dictionary of all
-the data being validated.  Note that at the point validators are called all
-data will still be strings (as ``do_html2python`` hasn't been called yet).
+the data being validated.
 
+.. admonition:: Note::
+
+    At the point validators are called all data will still be
+    strings (as ``do_html2python`` hasn't been called yet).
+
 Also, because consistency in user interfaces is important, we strongly urge you
 to put punctuation at the end of your validation messages.
 
+Ready-made Validators
+---------------------
+
+Writing your own validator is not difficult, but there are some situations
+that come up over and over again. Django comes with a number of validators
+that can be used directly in your code. All of these functions and classes
+reside in ``django/core/validators.py``.
+
+The following validators should all be self-explanatory. Each one provides a
+check for the given property:
+
+    * isAlphaNumeric
+    * isAlphaNumericURL
+    * isSlug
+    * isLowerCase
+    * isUpperCase
+    * isCommaSeparatedIntegerList
+    * isCommaSeparatedEmailList
+    * isValidIPAddress4
+    * isNotEmpty
+    * isOnlyDigits
+    * isNotOnlyDigits
+    * isInteger
+    * isOnlyLetters
+    * isValidANSIDate
+    * isValidANSITime
+    * isValidEmail
+    * isValidImage
+    * isValidImageURL
+    * isValidPhone
+    * isValidQuicktimeVideoURL
+    * isValidURL
+    * isValidHTML
+    * isWellFormedXml
+    * isWellFormedXmlFragment
+    * isExistingURL
+    * isValidUSState
+    * hasNoProfanities
+
+There are also a group of validators that are slightly more flexible. For
+these validators, you create a validator instance, passing in the parameters
+described below. The returned object is a callable that can be used as a
+validator.
+
+For example::
+
+    from django.core import validators
+    from django import forms
+
+    power_validator = validators.IsAPowerOf(2)
+
+    class InstallationManipulator(forms.Manipulator)
+        def __init__(self):
+            self.fields = (
+                ...
+                forms.IntegerField(field_name = "size",i
+                        validator_list=[power_validator])
+            )
+
+Here, ``validators.IsAPowerOf(...)`` returned something that could be used as
+a validator (in this case, a check that a number was a power of 2).
+
+Each of the standard validators that take parameters have an optional final
+argument (``error_message``) that is the message returned when validation
+fails. If no message is passed in, a default message is used.
+
+``AlwaysMatchesOtherField``
+    Takes a field name and the current field is valid if and only if its value
+    matches the contents of the other field.
+
+``ValidateIfOtherFieldEquals``
+    Takes three parameters: ``other_field``, ``other_value`` and
+    ``validator_list``, in that order. If ``other_field`` has a value of
+    ``other_vaue``, then the validators in ``validator_list`` are all run
+    against the current field.
+
+``RequiredIfOtherFieldNotGiven``
+    Takes the name of the other field and this field is only required if the
+    other field has no value.
+
+``RequiredIfOtherFieldsNotGiven``
+    Similar to ``RequiredIfOtherFieldNotGiven``, except that it takes a list
+    of field names and if any one of the supplied fields does not have a value
+    provided, the field being validated is required.
+
+``RequiredIfOtherFieldEquals`` and ``RequiredIfOtherFieldDoesNotEqual``
+    Each of these validator classes takes a field name and a value (in that
+    order). If the given field does (or does not have, in the latter case) the
+    given value, then the current field being validated is required.
+
+    Note that because validators are called before any ``do_html2python()``
+    functions, the value being compared against is a string. So
+    ``RequiredIfOtherFieldEquals('choice', '1')`` is correct, whilst
+    ``RequiredIfOtherFieldEquals('choice', 1)`` will never result in the
+    equality test succeeding.
+
+``IsLessThanOtherField``
+    Takes a field name and validates that the current field being validated
+    has a value that is less than (or equal to) the other field's value.
+    Again, comparisons are done using strings, so be cautious about using
+    this function to compare data that should be treated as another type. The
+    string "123" is less than the string "2", for example. If you don't want
+    string comparison here, you will need to write your own validator.
+
+``IsAPowerOf``
+    Takes an integer argument and when called as a validator, checks that the
+    field being validated is a power of the integer.
+
+``IsValidFloat``
+    Takes a maximum number of digits and number of decimal places (in that
+    order) and validates whether the field is a float with less than the
+    maximum number of digits and decimal place.
+
+``MatchesRegularExpression``
+    Takes a regular expression (a string) as a parameter and validates the
+    field value against it.
+
+``AnyValidator``
+    Takes a list of validators as a parameter. At validation time, if the
+    field successfully validates against any one of the validators, it passes
+    validation. The validators are tested in the order specified in the
+    original list.
+
+``URLMimeTypeCheck``
+    Used to validate URL fields. Takes a list of MIME types (such as
+    ``text/plain``) at creation time. At validation time, it verifies that the
+    field is indeed a URL and then tries to retrieve the content at the URL.
+    Validation succeeds if the content could be retrieved and it has a content
+    type from the list used to create the validator.
+
+``RelaxNGCompact``
+    Used to validate an XML document against a Relax NG compact schema. Takes
+    a file path to the location of the schema and an optional root element
+    (which is wrapped around the XML fragment before validation, if supplied).
+    At validation time, the XML fragment is validated against the schema using
+    the executable specified in the ``JING_PATH`` setting (see the settings_
+    document for more details).
+
 .. _`generic views`: http://www.djangoproject.com/documentation/generic_views/
+.. _`models API`: http://www.djangoproject.com/documentation/model_api/
+.. _settings: http://www.djangoproject.com/documentation/settings/
