diff --git a/django/newforms/models.py b/django/newforms/models.py
index 51ed16f..77b2b32 100644
--- a/django/newforms/models.py
+++ b/django/newforms/models.py
@@ -6,13 +6,15 @@ and database field objects.
 from django.utils.translation import ugettext_lazy as _
 from django.utils.encoding import smart_unicode
 from django.utils.datastructures import SortedDict
+from django.core.exceptions import ImproperlyConfigured
 
-from util import ValidationError
+from util import ValidationError, ErrorList
 from forms import BaseForm
 from fields import Field, ChoiceField, EMPTY_VALUES
 from widgets import Select, SelectMultiple, MultipleHiddenInput
 
 __all__ = (
+    'ModelForm', 'BaseModelForm', 'model_to_dict', 'fields_for_model',
     'save_instance', 'form_for_model', 'form_for_instance', 'form_for_fields',
     'ModelChoiceField', 'ModelMultipleChoiceField'
 )
@@ -132,6 +134,155 @@ def form_for_fields(field_list):
                          for f in field_list if f.editable])
     return type('FormForFields', (BaseForm,), {'base_fields': fields})
 
+
+# ModelForms #################################################################
+
+def model_to_dict(instance, fields=None, exclude=None):
+    """
+    Returns a dict containing the data in ``instance`` suitable for passing as
+    a Form's ``initial`` keyword argument.
+    
+    ``fields`` is an optional list of field names. If provided, only the named
+    fields will be included in the returned dict.
+    
+    ``exclude`` is an optional list of field names. If provided, the named
+    fields will be excluded from the returned dict, even if they are listed in
+    the ``fields`` argument.
+    """
+    # avoid a circular import
+    from django.db.models.fields.related import ManyToManyField
+    opts = instance._meta
+    data = {}
+    for f in opts.fields + opts.many_to_many:
+        if not f.editable:
+            continue
+        if fields and not f.name in fields:
+            continue
+        if exclude and f.name in exclude:
+            continue
+        if isinstance(f, ManyToManyField):
+            # If the object doesn't have a primry key yet, just use an empty
+            # list for its m2m fields. Calling f.value_from_object will raise
+            # an exception.
+            if instance.pk is None:
+                data[f.name] = []
+            else:
+                # MultipleChoiceWidget needs a list of pks, not object instances.
+                data[f.name] = [obj.pk for obj in f.value_from_object(instance)]
+        else:
+            data[f.name] = f.value_from_object(instance)
+    return data
+
+def fields_for_model(model, fields=None, exclude=None, formfield_callback=lambda f: f.formfield()):
+    """
+    Returns a ``SortedDict`` containing form fields for the given model.
+
+    ``fields`` is an optional list of field names. If provided, only the named
+    fields will be included in the returned fields.
+    
+    ``exclude`` is an optional list of field names. If provided, the named
+    fields will be excluded from the returned fields, even if they are listed
+    in the ``fields`` argument.
+    """
+    # TODO: if fields is provided, it would be nice to return fields in that order
+    field_list = []
+    opts = model._meta
+    for f in opts.fields + opts.many_to_many:
+        if not f.editable:
+            continue
+        if fields and not f.name in fields:
+            continue
+        if exclude and f.name in exclude:
+            continue
+        formfield = formfield_callback(f)
+        if formfield:
+            field_list.append((f.name, formfield))
+    return SortedDict(field_list)
+
+class ModelFormOptions(object):
+    def __init__(self, options=None):
+        self.model = getattr(options, 'model', None)
+        self.fields = getattr(options, 'fields', None)
+        self.exclude = getattr(options, 'exclude', None)
+
+class ModelFormMetaclass(type):
+    def __new__(cls, name, bases, attrs):
+        # TODO: no way to specify formfield_callback yet, do we need one, or
+        # should it be a special case for the admin?
+        fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
+        fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))
+
+        # If this class is subclassing another Form, add that Form's fields.
+        # Note that we loop over the bases in *reverse*. This is necessary in
+        # order to preserve the correct order of fields.
+        for base in bases[::-1]:
+            if hasattr(base, 'base_fields'):
+                fields = base.base_fields.items() + fields
+        declared_fields = SortedDict(fields)
+
+        opts = ModelFormOptions(attrs.get('Meta', None))
+        attrs['_meta'] = opts
+
+        # Don't allow more than one Meta model defenition in bases. The fields
+        # would be generated correctly, but the save method won't deal with
+        # more than one object.
+        base_models = []
+        for base in bases:
+            base_opts = getattr(base, '_meta', None)
+            base_model = getattr(base_opts, 'model', None)
+            if base_model is not None:
+                base_models.append(base_model)
+        if len(base_models) > 1:
+            raise ImproperlyConfigured("%s's base classes define more than one model." % name)
+
+        # If a model is defined, extract form fields from it and add them to base_fields
+        if attrs['_meta'].model is not None:
+            # Don't allow a subclass to define a Meta model if a parent class has.
+            # Technically the right fields would be generated, but the save 
+            # method will not deal with more than one model.
+            for base in bases:
+                base_opts = getattr(base, '_meta', None)
+                base_model = getattr(base_opts, 'model', None)
+                if base_model is not None:
+                    raise ImproperlyConfigured('%s defines more than one model.' % name)
+            model_fields = fields_for_model(opts.model, opts.fields, opts.exclude)
+            # fields declared in base classes override fields from the model
+            model_fields.update(declared_fields)
+            attrs['base_fields'] = model_fields
+        else:
+            attrs['base_fields'] = declared_fields
+        return type.__new__(cls, name, bases, attrs)
+
+class BaseModelForm(BaseForm):
+    def __init__(self, instance, data=None, files=None, auto_id='id_%s', prefix=None,
+                 initial=None, error_class=ErrorList, label_suffix=':'):
+        self.instance = instance
+        opts = self._meta
+        object_data = model_to_dict(instance, opts.fields, opts.exclude)
+        # if initial was provided, it should override the values from instance
+        if initial is not None:
+            object_data.update(initial)
+        BaseForm.__init__(self, data, files, auto_id, prefix, object_data, error_class, label_suffix)
+
+    def save(self, commit=True):
+        """
+        Saves this ``form``'s cleaned_data into model instance ``self.instance``.
+
+        If commit=True, then the changes to ``instance`` will be saved to the
+        database. Returns ``instance``.
+        """
+        if self.instance.pk is None:
+            fail_message = 'created'
+        else:
+            fail_message = 'changed'
+        return save_instance(self, self.instance, self._meta.fields, fail_message, commit)
+
+class ModelForm(BaseModelForm):
+    __metaclass__ = ModelFormMetaclass
+
+
+# Fields #####################################################################
+
 class QuerySetIterator(object):
     def __init__(self, queryset, empty_label, cache_choices):
         self.queryset = queryset
@@ -142,7 +293,7 @@ class QuerySetIterator(object):
         if self.empty_label is not None:
             yield (u"", self.empty_label)
         for obj in self.queryset:
-            yield (obj._get_pk_val(), smart_unicode(obj))
+            yield (obj.pk, smart_unicode(obj))
         # Clear the QuerySet cache if required.
         if not self.cache_choices:
             self.queryset._result_cache = None
diff --git a/docs/form_for_model.txt b/docs/form_for_model.txt
new file mode 100644
index 0000000..6761c15
--- /dev/null
+++ b/docs/form_for_model.txt
@@ -0,0 +1,418 @@
+Generating forms for models
+===========================
+
+If you're building a database-driven app, chances are you'll have forms that
+map closely to Django models. For instance, you might have a ``BlogComment``
+model, and you want to create a form that lets people submit comments. In this
+case, it would be redundant to define the field types in your form, because
+you've already defined the fields in your model.
+
+For this reason, Django provides a few helper functions that let you create a
+``Form`` class from a Django model.
+
+``form_for_model()``
+--------------------
+
+The method ``django.newforms.form_for_model()`` creates a form based on the
+definition of a specific model. Pass it the model class, and it will return a
+``Form`` class that contains a form field for each model field.
+
+For example::
+
+    >>> from django.newforms import form_for_model
+
+    # Create the form class.
+    >>> ArticleForm = form_for_model(Article)
+
+    # Create an empty form instance.
+    >>> f = ArticleForm()
+
+It bears repeating that ``form_for_model()`` takes the model *class*, not a
+model instance, and it returns a ``Form`` *class*, not a ``Form`` instance.
+
+Field types
+~~~~~~~~~~~
+
+The generated ``Form`` class will have a form field for every model field. Each
+model field has a corresponding default form field. For example, a
+``CharField`` on a model is represented as a ``CharField`` on a form. A
+model ``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is
+the full list of conversions:
+
+    ===============================  ========================================
+    Model field                      Form field
+    ===============================  ========================================
+    ``AutoField``                    Not represented in the form
+    ``BooleanField``                 ``BooleanField``
+    ``CharField``                    ``CharField`` with ``max_length`` set to
+                                     the model field's ``max_length``
+    ``CommaSeparatedIntegerField``   ``CharField``
+    ``DateField``                    ``DateField``
+    ``DateTimeField``                ``DateTimeField``
+    ``DecimalField``                 ``DecimalField``
+    ``EmailField``                   ``EmailField``
+    ``FileField``                    ``FileField``
+    ``FilePathField``                ``CharField``
+    ``FloatField``                   ``FloatField``
+    ``ForeignKey``                   ``ModelChoiceField`` (see below)
+    ``ImageField``                   ``ImageField``
+    ``IntegerField``                 ``IntegerField``
+    ``IPAddressField``               ``IPAddressField``
+    ``ManyToManyField``              ``ModelMultipleChoiceField`` (see
+                                     below)
+    ``NullBooleanField``             ``CharField``
+    ``PhoneNumberField``             ``USPhoneNumberField``
+                                     (from ``django.contrib.localflavor.us``)
+    ``PositiveIntegerField``         ``IntegerField``
+    ``PositiveSmallIntegerField``    ``IntegerField``
+    ``SlugField``                    ``CharField``
+    ``SmallIntegerField``            ``IntegerField``
+    ``TextField``                    ``CharField`` with ``widget=Textarea``
+    ``TimeField``                    ``TimeField``
+    ``URLField``                     ``URLField`` with ``verify_exists`` set
+                                     to the model field's ``verify_exists``
+    ``USStateField``                 ``CharField`` with
+                                     ``widget=USStateSelect``
+                                     (``USStateSelect`` is from
+                                     ``django.contrib.localflavor.us``)
+    ``XMLField``                     ``CharField`` with ``widget=Textarea``
+    ===============================  ========================================
+
+
+.. note::
+    The ``FloatField`` form field and ``DecimalField`` model and form fields
+    are new in the development version.
+
+As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field
+types are special cases:
+
+    * ``ForeignKey`` is represented by ``django.newforms.ModelChoiceField``,
+      which is a ``ChoiceField`` whose choices are a model ``QuerySet``.
+
+    * ``ManyToManyField`` is represented by
+      ``django.newforms.ModelMultipleChoiceField``, which is a
+      ``MultipleChoiceField`` whose choices are a model ``QuerySet``.
+
+In addition, each generated form field has attributes set as follows:
+
+    * If the model field has ``blank=True``, then ``required`` is set to
+      ``False`` on the form field. Otherwise, ``required=True``.
+
+    * The form field's ``label`` is set to the ``verbose_name`` of the model
+      field, with the first character capitalized.
+
+    * The form field's ``help_text`` is set to the ``help_text`` of the model
+      field.
+
+    * If the model field has ``choices`` set, then the form field's ``widget``
+      will be set to ``Select``, with choices coming from the model field's
+      ``choices``. The choices will normally include the blank choice which is
+      selected by default. If the field is required, this forces the user to
+      make a selection. The blank choice will not be included if the model
+      field has ``blank=False`` and an explicit ``default`` value (the
+      ``default`` value will be initially selected instead).
+
+Finally, note that you can override the form field used for a given model
+field. See "Overriding the default field types" below.
+
+A full example
+~~~~~~~~~~~~~~
+
+Consider this set of models::
+
+    from django.db import models
+
+    TITLE_CHOICES = (
+        ('MR', 'Mr.'),
+        ('MRS', 'Mrs.'),
+        ('MS', 'Ms.'),
+    )
+
+    class Author(models.Model):
+        name = models.CharField(max_length=100)
+        title = models.CharField(max_length=3, choices=TITLE_CHOICES)
+        birth_date = models.DateField(blank=True, null=True)
+
+        def __unicode__(self):
+            return self.name
+
+    class Book(models.Model):
+        name = models.CharField(max_length=100)
+        authors = models.ManyToManyField(Author)
+
+With these models, a call to ``form_for_model(Author)`` would return a ``Form``
+class equivalent to this::
+
+    class AuthorForm(forms.Form):
+        name = forms.CharField(max_length=100)
+        title = forms.CharField(max_length=3,
+                    widget=forms.Select(choices=TITLE_CHOICES))
+        birth_date = forms.DateField(required=False)
+
+A call to ``form_for_model(Book)`` would return a ``Form`` class equivalent to
+this::
+
+    class BookForm(forms.Form):
+        name = forms.CharField(max_length=100)
+        authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
+
+The ``save()`` method
+~~~~~~~~~~~~~~~~~~~~~
+
+Every form produced by ``form_for_model()`` also has a ``save()`` method. This
+method creates and saves a database object from the data bound to the form. For
+example::
+
+    # Create a form instance from POST data.
+    >>> f = ArticleForm(request.POST)
+
+    # Save a new Article object from the form's data.
+    >>> new_article = f.save()
+
+Note that ``save()`` will raise a ``ValueError`` if the data in the form
+doesn't validate -- i.e., ``if form.errors``.
+
+This ``save()`` method accepts an optional ``commit`` keyword argument, which
+accepts either ``True`` or ``False``. If you call ``save()`` with
+``commit=False``, then it will return an object that hasn't yet been saved to
+the database. In this case, it's up to you to call ``save()`` on the resulting
+model instance. This is useful if you want to do custom processing on the
+object before saving it. ``commit`` is ``True`` by default.
+
+Another side effect of using ``commit=False`` is seen when your model has
+a many-to-many relation with another model. If your model has a many-to-many
+relation and you specify ``commit=False`` when you save a form, Django cannot
+immediately save the form data for the many-to-many relation. This is because
+it isn't possible to save many-to-many data for an instance until the instance
+exists in the database.
+
+To work around this problem, every time you save a form using ``commit=False``,
+Django adds a ``save_m2m()`` method to the form created by ``form_for_model``.
+After you've manually saved the instance produced by the form, you can invoke
+``save_m2m()`` to save the many-to-many form data. For example::
+
+    # Create a form instance with POST data.
+    >>> f = AuthorForm(request.POST)
+
+    # Create, but don't save the new author instance.
+    >>> new_author = f.save(commit=False)
+
+    # Modify the author in some way.
+    >>> new_author.some_field = 'some_value'
+
+    # Save the new instance.
+    >>> new_author.save()
+
+    # Now, save the many-to-many data for the form.
+    >>> f.save_m2m()
+
+Calling ``save_m2m()`` is only required if you use ``save(commit=False)``.
+When you use a simple ``save()`` on a form, all data -- including
+many-to-many data -- is saved without the need for any additional method calls.
+For example::
+
+    # Create a form instance with POST data.
+    >>> f = AuthorForm(request.POST)
+
+    # Create and save the new author instance. There's no need to do anything else.
+    >>> new_author = f.save()
+
+Using an alternate base class
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you want to add custom methods to the form generated by
+``form_for_model()``, write a class that extends ``django.newforms.BaseForm``
+and contains your custom methods. Then, use the ``form`` argument to
+``form_for_model()`` to tell it to use your custom form as its base class.
+For example::
+
+    # Create the new base class.
+    >>> class MyBase(BaseForm):
+    ...     def my_method(self):
+    ...         # Do whatever the method does
+
+    # Create the form class with a different base class.
+    >>> ArticleForm = form_for_model(Article, form=MyBase)
+
+    # Instantiate the form.
+    >>> f = ArticleForm()
+
+    # Use the base class method.
+    >>> f.my_method()
+
+Using a subset of fields on the form
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+**New in Django development version**
+
+In some cases, you may not want all the model fields to appear on the generated
+form. There are two ways of telling ``form_for_model()`` to use only a subset
+of the model fields:
+
+    1. Set ``editable=False`` on the model field. As a result, *any* form
+       created from the model via ``form_for_model()`` will not include that
+       field.
+
+    2. Use the ``fields`` argument to ``form_for_model()``. This argument, if
+       given, should be a list of field names to include in the form.
+
+       For example, if you want a form for the ``Author`` model (defined above)
+       that includes only the ``name`` and ``title`` fields, you would specify
+       ``fields`` like this::
+
+           PartialArticleForm = form_for_model(Author, fields=('name', 'title'))
+
+.. note::
+
+    If you specify ``fields`` when creating a form with ``form_for_model()``,
+    then the fields that are *not* specified will not be set by the form's
+    ``save()`` method. Django will prevent any attempt to save an incomplete
+    model, so if the model does not allow the missing fields to be empty, and
+    does not provide a default value for the missing fields, any attempt to
+    ``save()`` a ``form_for_model`` with missing fields will fail. To avoid
+    this failure, you must use ``save(commit=False)`` and manually set any
+    extra required fields::
+
+        instance = form.save(commit=False)
+        instance.required_field = 'new value'
+        instance.save()
+
+    See the `section on saving forms`_ for more details on using
+    ``save(commit=False)``.
+
+.. _section on saving forms: `The save() method`_
+
+Overriding the default field types
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The default field types, as described in the "Field types" table above, are
+sensible defaults; if you have a ``DateField`` in your model, chances are you'd
+want that to be represented as a ``DateField`` in your form. But
+``form_for_model()`` gives you the flexibility of changing the form field type
+for a given model field. You do this by specifying a **formfield callback**.
+
+A formfield callback is a function that, when provided with a model field,
+returns a form field instance. When constructing a form, ``form_for_model()``
+asks the formfield callback to provide form field types.
+
+By default, ``form_for_model()`` calls the ``formfield()`` method on the model
+field::
+
+    def default_callback(field, **kwargs):
+        return field.formfield(**kwargs)
+
+The ``kwargs`` are any keyword arguments that might be passed to the form
+field, such as ``required=True`` or ``label='Foo'``.
+
+For example, if you wanted to use ``MyDateFormField`` for any ``DateField``
+field on the model, you could define the callback::
+
+    >>> def my_callback(field, **kwargs):
+    ...     if isinstance(field, models.DateField):
+    ...         return MyDateFormField(**kwargs)
+    ...     else:
+    ...         return field.formfield(**kwargs)
+
+    >>> ArticleForm = form_for_model(Article, formfield_callback=my_callback)
+
+Note that your callback needs to handle *all* possible model field types, not
+just the ones that you want to behave differently to the default. That's why
+this example has an ``else`` clause that implements the default behavior.
+
+.. warning::
+    The field that is passed into the ``formfield_callback`` function in
+    ``form_for_model()`` and ``form_for_instance`` is the field instance from
+    your model's class. You **must not** alter that object at all; treat it
+    as read-only!
+
+    If you make any alterations to that object, it will affect any future
+    users of the model class, because you will have changed the field object
+    used to construct the class. This is almost certainly what you don't want
+    to have happen.
+
+Finding the model associated with a form
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The model class that was used to construct the form is available
+using the ``_model`` property of the generated form::
+
+    >>> ArticleForm = form_for_model(Article)
+    >>> ArticleForm._model
+    <class 'myapp.models.Article'>
+
+``form_for_instance()``
+-----------------------
+
+``form_for_instance()`` is like ``form_for_model()``, but it takes a model
+instance instead of a model class::
+
+    # Create an Author.
+    >>> a = Author(name='Joe Smith', title='MR', birth_date=None)
+    >>> a.save()
+
+    # Create a form for this particular Author.
+    >>> AuthorForm = form_for_instance(a)
+
+    # Instantiate the form.
+    >>> f = AuthorForm()
+
+When a form created by ``form_for_instance()`` is created, the initial data
+values for the form fields are drawn from the instance. However, this data is
+not bound to the form. You will need to bind data to the form before the form
+can be saved.
+
+Unlike ``form_for_model()``, a choice field in form created by
+``form_for_instance()`` will not include the blank choice if the respective
+model field has ``blank=False``. The initial choice is drawn from the instance.
+
+When you call ``save()`` on a form created by ``form_for_instance()``,
+the database instance will be updated. As in ``form_for_model()``, ``save()``
+will raise ``ValueError`` if the data doesn't validate.
+
+``form_for_instance()`` has ``form``, ``fields`` and ``formfield_callback``
+arguments that behave the same way as they do for ``form_for_model()``.
+
+Let's modify the earlier `contact form`_ view example a little bit. Suppose we
+have a ``Message`` model that holds each contact submission. Something like::
+
+    class Message(models.Model):
+        subject = models.CharField(max_length=100)
+        message = models.TextField()
+        sender = models.EmailField()
+        cc_myself = models.BooleanField(required=False)
+
+You could use this model to create a form (using ``form_for_model()``). You
+could also use existing ``Message`` instances to create a form for editing
+messages. The `simple example view`_ can be changed slightly to accept the ``id`` value
+of an existing ``Message`` and present it for editing::
+
+    def contact_edit(request, msg_id):
+        # Create the form from the message id.
+        message = get_object_or_404(Message, id=msg_id)
+        ContactForm = form_for_instance(message)
+
+        if request.method == 'POST':
+            form = ContactForm(request.POST)
+            if form.is_valid():
+                form.save()
+                return HttpResponseRedirect('/url/on_success/')
+        else:
+            form = ContactForm()
+        return render_to_response('contact.html', {'form': form})
+
+Aside from how we create the ``ContactForm`` class here, the main point to
+note is that the form display in the ``GET`` branch of the function
+will use the values from the ``message`` instance as initial values for the
+form field.
+
+.. _contact form: ../newforms/#simple-view-example
+.. _`simple example view`: ../newforms/#simple-view-example
+
+When should you use ``form_for_model()`` and ``form_for_instance()``?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The ``form_for_model()`` and ``form_for_instance()`` functions are meant to be
+shortcuts for the common case. If you want to create a form whose fields map to
+more than one model, or a form that contains fields that *aren't* on a model,
+you shouldn't use these shortcuts. Creating a ``Form`` class the "long" way
+isn't that difficult, after all.
diff --git a/docs/modelforms.txt b/docs/modelforms.txt
new file mode 100644
index 0000000..5e94128
--- /dev/null
+++ b/docs/modelforms.txt
@@ -0,0 +1,310 @@
+==========================
+Using newforms with models
+==========================
+
+``ModelForm``
+=============
+
+If you're building a database-driven app, chances are you'll have forms that
+map closely to Django models. For instance, you might have a ``BlogComment``
+model, and you want to create a form that lets people submit comments. In this
+case, it would be redundant to define the field types in your form, because
+you've already defined the fields in your model.
+
+For this reason, Django provides a helper class that let you create a ``Form``
+class from a Django model.
+
+For example::
+
+    >>> from django.newforms import ModelForm
+    
+    # Create the form class.
+    >>> class ArticleForm(ModelForm):
+    ...     class Meta:
+    ...         model = Article
+
+    # Creating a form to add an article.
+    >>> article\ = Article()
+    >>> form = ArticleForm(article)
+
+    # Creating a form to change an existing article.
+    >>> article = Article.objects.get(pk=1)
+    >>> form = ArticleForm(article)
+
+Field types
+-----------
+
+The generated ``Form`` class will have a form field for every model field. Each
+model field has a corresponding default form field. For example, a
+``CharField`` on a model is represented as a ``CharField`` on a form. A
+model ``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is
+the full list of conversions:
+
+    ===============================  ========================================
+    Model field                      Form field
+    ===============================  ========================================
+    ``AutoField``                    Not represented in the form
+    ``BooleanField``                 ``BooleanField``
+    ``CharField``                    ``CharField`` with ``max_length`` set to
+                                     the model field's ``max_length``
+    ``CommaSeparatedIntegerField``   ``CharField``
+    ``DateField``                    ``DateField``
+    ``DateTimeField``                ``DateTimeField``
+    ``DecimalField``                 ``DecimalField``
+    ``EmailField``                   ``EmailField``
+    ``FileField``                    ``FileField``
+    ``FilePathField``                ``CharField``
+    ``FloatField``                   ``FloatField``
+    ``ForeignKey``                   ``ModelChoiceField`` (see below)
+    ``ImageField``                   ``ImageField``
+    ``IntegerField``                 ``IntegerField``
+    ``IPAddressField``               ``IPAddressField``
+    ``ManyToManyField``              ``ModelMultipleChoiceField`` (see
+                                     below)
+    ``NullBooleanField``             ``CharField``
+    ``PhoneNumberField``             ``USPhoneNumberField``
+                                     (from ``django.contrib.localflavor.us``)
+    ``PositiveIntegerField``         ``IntegerField``
+    ``PositiveSmallIntegerField``    ``IntegerField``
+    ``SlugField``                    ``CharField``
+    ``SmallIntegerField``            ``IntegerField``
+    ``TextField``                    ``CharField`` with ``widget=Textarea``
+    ``TimeField``                    ``TimeField``
+    ``URLField``                     ``URLField`` with ``verify_exists`` set
+                                     to the model field's ``verify_exists``
+    ``USStateField``                 ``CharField`` with
+                                     ``widget=USStateSelect``
+                                     (``USStateSelect`` is from
+                                     ``django.contrib.localflavor.us``)
+    ``XMLField``                     ``CharField`` with ``widget=Textarea``
+    ===============================  ========================================
+
+
+.. note::
+    The ``FloatField`` form field and ``DecimalField`` model and form fields
+    are new in the development version.
+
+As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field
+types are special cases:
+
+    * ``ForeignKey`` is represented by ``django.newforms.ModelChoiceField``,
+      which is a ``ChoiceField`` whose choices are a model ``QuerySet``.
+
+    * ``ManyToManyField`` is represented by
+      ``django.newforms.ModelMultipleChoiceField``, which is a
+      ``MultipleChoiceField`` whose choices are a model ``QuerySet``.
+
+In addition, each generated form field has attributes set as follows:
+
+    * If the model field has ``blank=True``, then ``required`` is set to
+      ``False`` on the form field. Otherwise, ``required=True``.
+
+    * The form field's ``label`` is set to the ``verbose_name`` of the model
+      field, with the first character capitalized.
+
+    * The form field's ``help_text`` is set to the ``help_text`` of the model
+      field.
+
+    * If the model field has ``choices`` set, then the form field's ``widget``
+      will be set to ``Select``, with choices coming from the model field's
+      ``choices``. The choices will normally include the blank choice which is
+      selected by default. If the field is required, this forces the user to
+      make a selection. The blank choice will not be included if the model
+      field has ``blank=False`` and an explicit ``default`` value (the
+      ``default`` value will be initially selected instead).
+
+Finally, note that you can override the form field used for a given model
+field. See "Overriding the default field types" below.
+
+A full example
+--------------
+
+Consider this set of models::
+
+    from django.db import models
+
+    TITLE_CHOICES = (
+        ('MR', 'Mr.'),
+        ('MRS', 'Mrs.'),
+        ('MS', 'Ms.'),
+    )
+
+    class Author(models.Model):
+        name = models.CharField(max_length=100)
+        title = models.CharField(max_length=3, choices=TITLE_CHOICES)
+        birth_date = models.DateField(blank=True, null=True)
+
+        def __unicode__(self):
+            return self.name
+
+    class Book(models.Model):
+        name = models.CharField(max_length=100)
+        authors = models.ManyToManyField(Author)
+
+    class AuthorForm(ModelForm):
+        class Meta:
+            model = Author
+
+    class BookForm(ModelForm):
+        class Meta:
+            model = Book
+
+With these models, the ``ModelForm`` subclasses above would be roughly
+equivalent to this (the only difference being the ``save()`` method, which
+we'll discuss in a moment.)::
+
+    class AuthorForm(forms.Form):
+        name = forms.CharField(max_length=100)
+        title = forms.CharField(max_length=3,
+                    widget=forms.Select(choices=TITLE_CHOICES))
+        birth_date = forms.DateField(required=False)
+
+    class BookForm(forms.Form):
+        name = forms.CharField(max_length=100)
+        authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
+
+The ``save()`` method
+---------------------
+
+Every form produced by ``ModelForm`` also has a ``save()`` method. This
+method creates and saves a database object from the data bound to the form.
+A subclass of ``ModelForm`` also requires a model instance as the first
+arument to its constructor. For example::
+
+    # Create a form instance from POST data.
+    >>> a = Article()
+    >>> f = ArticleForm(a, request.POST)
+
+    # Save a new Article object from the form's data.
+    >>> new_article = f.save()
+
+Note that ``save()`` will raise a ``ValueError`` if the data in the form
+doesn't validate -- i.e., ``if form.errors``.
+
+This ``save()`` method accepts an optional ``commit`` keyword argument, which
+accepts either ``True`` or ``False``. If you call ``save()`` with
+``commit=False``, then it will return an object that hasn't yet been saved to
+the database. In this case, it's up to you to call ``save()`` on the resulting
+model instance. This is useful if you want to do custom processing on the
+object before saving it. ``commit`` is ``True`` by default.
+
+Another side effect of using ``commit=False`` is seen when your model has
+a many-to-many relation with another model. If your model has a many-to-many
+relation and you specify ``commit=False`` when you save a form, Django cannot
+immediately save the form data for the many-to-many relation. This is because
+it isn't possible to save many-to-many data for an instance until the instance
+exists in the database.
+
+To work around this problem, every time you save a form using ``commit=False``,
+Django adds a ``save_m2m()`` method to your ``ModelForm`` subclass. After
+you've manually saved the instance produced by the form, you can invoke
+``save_m2m()`` to save the many-to-many form data. For example::
+
+    # Create a form instance with POST data.
+    >>> a = Author()
+    >>> f = AuthorForm(a, request.POST)
+
+    # Create, but don't save the new author instance.
+    >>> new_author = f.save(commit=False)
+
+    # Modify the author in some way.
+    >>> new_author.some_field = 'some_value'
+
+    # Save the new instance.
+    >>> new_author.save()
+
+    # Now, save the many-to-many data for the form.
+    >>> f.save_m2m()
+
+Calling ``save_m2m()`` is only required if you use ``save(commit=False)``.
+When you use a simple ``save()`` on a form, all data -- including
+many-to-many data -- is saved without the need for any additional method calls.
+For example::
+
+    # Create a form instance with POST data.
+    >>> a = Author()
+    >>> f = AuthorForm(a, request.POST)
+
+    # Create and save the new author instance. There's no need to do anything else.
+    >>> new_author = f.save()
+
+Using a subset of fields on the form
+------------------------------------
+
+In some cases, you may not want all the model fields to appear on the generated
+form. There are three ways of telling ``ModelForm`` to use only a subset of the
+model fields:
+
+    1. Set ``editable=False`` on the model field. As a result, *any* form
+       created from the model via ``ModelForm`` will not include that
+       field.
+
+    2. Use the ``fields`` attribute of the ``ModelForm``'s inner ``Meta`` class.
+       This attribute, if given, should be a list of field names to include in
+       the form.
+
+    3. Use the ``exclude`` attribute of the ``ModelForm``'s inner ``Meta`` class.
+       This attribute, if given, should be a list of field names to exclude
+       the form.
+
+       For example, if you want a form for the ``Author`` model (defined above)
+       that includes only the ``name`` and ``title`` fields, you would specify
+       ``fields`` or  ``exclude`` like this::
+
+          class PartialAuthorForm(ModelForm):
+              class Meta:
+                  model = Author
+                  fields = ('name', 'title')
+
+          class PartialAuthorForm(ModelForm):
+              class Meta:
+                  model = Author
+                  exclude = ('birth_date',)
+
+        Since the Author model has only 3 fields, 'name', 'title', and
+        'birth_date', the forms above will contain exactly the same fields.
+
+.. note::
+
+    If you specify ``fields`` or ``exclude`` when creating a form with
+    ``ModelForm``, then the fields that are not in the resulting form will not
+    be set by the form's ``save()`` method. Django will prevent any attempt to
+    save an incomplete model, so if the model does not allow the missing fields
+    to be empty, and does not provide a default value for the missing fields,
+    any attempt to ``save()`` a ``ModelForm`` with missing fields will fail.
+    To avoid this failure, you must instantiate your model with initial values
+    for the missing, but required fields, or use ``save(commit=False)`` and
+    manually set anyextra required fields::
+    
+        instance = Instance(requiured_field='value')
+        form = InstanceForm(instance, request.POST)
+        new_instance = form.save()
+
+        instance = form.save(commit=False)
+        instance.required_field = 'new value'
+        new_instance = instance.save()
+
+    See the `section on saving forms`_ for more details on using
+    ``save(commit=False)``.
+
+.. _section on saving forms: `The save() method`_
+
+Overriding the default field types
+----------------------------------
+
+The default field types, as described in the "Field types" table above, are
+sensible defaults; if you have a ``DateField`` in your model, chances are you'd
+want that to be represented as a ``DateField`` in your form. But
+``ModelForm`` gives you the flexibility of changing the form field type
+for a given model field. You do this by declaratively specifying fields like
+you would in a regular ``Form``. Declared fields will override the default
+ones generated by using the ``model`` attribute.
+
+For example, if you wanted to use ``MyDateFormField`` for the ``pub_date``
+field, you could do the following::
+
+    >>> class ArticleForm(ModelForm):
+    ...     pub_date = MyDateFormField()
+    ...
+    ...     class Meta:
+    ...         model = Article
diff --git a/docs/newforms.txt b/docs/newforms.txt
index f26afcb..75573ac 100644
--- a/docs/newforms.txt
+++ b/docs/newforms.txt
@@ -1768,421 +1768,14 @@ You can then use this field whenever you have a form that requires a comment::
 Generating forms for models
 ===========================
 
-If you're building a database-driven app, chances are you'll have forms that
-map closely to Django models. For instance, you might have a ``BlogComment``
-model, and you want to create a form that lets people submit comments. In this
-case, it would be redundant to define the field types in your form, because
-you've already defined the fields in your model.
+The prefered way of generating forms that work with models is explained in the
+`ModelForms documentation`_.
 
-For this reason, Django provides a few helper functions that let you create a
-``Form`` class from a Django model.
+Looking for the ``form_for_model`` and ``form_for_instance`` documentation?
+They've been deprecated, but you can still `view the documentation`_.
 
-``form_for_model()``
---------------------
-
-The method ``django.newforms.form_for_model()`` creates a form based on the
-definition of a specific model. Pass it the model class, and it will return a
-``Form`` class that contains a form field for each model field.
-
-For example::
-
-    >>> from django.newforms import form_for_model
-
-    # Create the form class.
-    >>> ArticleForm = form_for_model(Article)
-
-    # Create an empty form instance.
-    >>> f = ArticleForm()
-
-It bears repeating that ``form_for_model()`` takes the model *class*, not a
-model instance, and it returns a ``Form`` *class*, not a ``Form`` instance.
-
-Field types
-~~~~~~~~~~~
-
-The generated ``Form`` class will have a form field for every model field. Each
-model field has a corresponding default form field. For example, a
-``CharField`` on a model is represented as a ``CharField`` on a form. A
-model ``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is
-the full list of conversions:
-
-    ===============================  ========================================
-    Model field                      Form field
-    ===============================  ========================================
-    ``AutoField``                    Not represented in the form
-    ``BooleanField``                 ``BooleanField``
-    ``CharField``                    ``CharField`` with ``max_length`` set to
-                                     the model field's ``max_length``
-    ``CommaSeparatedIntegerField``   ``CharField``
-    ``DateField``                    ``DateField``
-    ``DateTimeField``                ``DateTimeField``
-    ``DecimalField``                 ``DecimalField``
-    ``EmailField``                   ``EmailField``
-    ``FileField``                    ``FileField``
-    ``FilePathField``                ``CharField``
-    ``FloatField``                   ``FloatField``
-    ``ForeignKey``                   ``ModelChoiceField`` (see below)
-    ``ImageField``                   ``ImageField``
-    ``IntegerField``                 ``IntegerField``
-    ``IPAddressField``               ``IPAddressField``
-    ``ManyToManyField``              ``ModelMultipleChoiceField`` (see
-                                     below)
-    ``NullBooleanField``             ``CharField``
-    ``PhoneNumberField``             ``USPhoneNumberField``
-                                     (from ``django.contrib.localflavor.us``)
-    ``PositiveIntegerField``         ``IntegerField``
-    ``PositiveSmallIntegerField``    ``IntegerField``
-    ``SlugField``                    ``CharField``
-    ``SmallIntegerField``            ``IntegerField``
-    ``TextField``                    ``CharField`` with ``widget=Textarea``
-    ``TimeField``                    ``TimeField``
-    ``URLField``                     ``URLField`` with ``verify_exists`` set
-                                     to the model field's ``verify_exists``
-    ``USStateField``                 ``CharField`` with
-                                     ``widget=USStateSelect``
-                                     (``USStateSelect`` is from
-                                     ``django.contrib.localflavor.us``)
-    ``XMLField``                     ``CharField`` with ``widget=Textarea``
-    ===============================  ========================================
-
-
-.. note::
-    The ``FloatField`` form field and ``DecimalField`` model and form fields
-    are new in the development version.
-
-As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field
-types are special cases:
-
-    * ``ForeignKey`` is represented by ``django.newforms.ModelChoiceField``,
-      which is a ``ChoiceField`` whose choices are a model ``QuerySet``.
-
-    * ``ManyToManyField`` is represented by
-      ``django.newforms.ModelMultipleChoiceField``, which is a
-      ``MultipleChoiceField`` whose choices are a model ``QuerySet``.
-
-In addition, each generated form field has attributes set as follows:
-
-    * If the model field has ``blank=True``, then ``required`` is set to
-      ``False`` on the form field. Otherwise, ``required=True``.
-
-    * The form field's ``label`` is set to the ``verbose_name`` of the model
-      field, with the first character capitalized.
-
-    * The form field's ``help_text`` is set to the ``help_text`` of the model
-      field.
-
-    * If the model field has ``choices`` set, then the form field's ``widget``
-      will be set to ``Select``, with choices coming from the model field's
-      ``choices``. The choices will normally include the blank choice which is
-      selected by default. If the field is required, this forces the user to
-      make a selection. The blank choice will not be included if the model
-      field has ``blank=False`` and an explicit ``default`` value (the
-      ``default`` value will be initially selected instead).
-
-Finally, note that you can override the form field used for a given model
-field. See "Overriding the default field types" below.
-
-A full example
-~~~~~~~~~~~~~~
-
-Consider this set of models::
-
-    from django.db import models
-
-    TITLE_CHOICES = (
-        ('MR', 'Mr.'),
-        ('MRS', 'Mrs.'),
-        ('MS', 'Ms.'),
-    )
-
-    class Author(models.Model):
-        name = models.CharField(max_length=100)
-        title = models.CharField(max_length=3, choices=TITLE_CHOICES)
-        birth_date = models.DateField(blank=True, null=True)
-
-        def __unicode__(self):
-            return self.name
-
-    class Book(models.Model):
-        name = models.CharField(max_length=100)
-        authors = models.ManyToManyField(Author)
-
-With these models, a call to ``form_for_model(Author)`` would return a ``Form``
-class equivalent to this::
-
-    class AuthorForm(forms.Form):
-        name = forms.CharField(max_length=100)
-        title = forms.CharField(max_length=3,
-                    widget=forms.Select(choices=TITLE_CHOICES))
-        birth_date = forms.DateField(required=False)
-
-A call to ``form_for_model(Book)`` would return a ``Form`` class equivalent to
-this::
-
-    class BookForm(forms.Form):
-        name = forms.CharField(max_length=100)
-        authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
-
-The ``save()`` method
-~~~~~~~~~~~~~~~~~~~~~
-
-Every form produced by ``form_for_model()`` also has a ``save()`` method. This
-method creates and saves a database object from the data bound to the form. For
-example::
-
-    # Create a form instance from POST data.
-    >>> f = ArticleForm(request.POST)
-
-    # Save a new Article object from the form's data.
-    >>> new_article = f.save()
-
-Note that ``save()`` will raise a ``ValueError`` if the data in the form
-doesn't validate -- i.e., ``if form.errors``.
-
-This ``save()`` method accepts an optional ``commit`` keyword argument, which
-accepts either ``True`` or ``False``. If you call ``save()`` with
-``commit=False``, then it will return an object that hasn't yet been saved to
-the database. In this case, it's up to you to call ``save()`` on the resulting
-model instance. This is useful if you want to do custom processing on the
-object before saving it. ``commit`` is ``True`` by default.
-
-Another side effect of using ``commit=False`` is seen when your model has
-a many-to-many relation with another model. If your model has a many-to-many
-relation and you specify ``commit=False`` when you save a form, Django cannot
-immediately save the form data for the many-to-many relation. This is because
-it isn't possible to save many-to-many data for an instance until the instance
-exists in the database.
-
-To work around this problem, every time you save a form using ``commit=False``,
-Django adds a ``save_m2m()`` method to the form created by ``form_for_model``.
-After you've manually saved the instance produced by the form, you can invoke
-``save_m2m()`` to save the many-to-many form data. For example::
-
-    # Create a form instance with POST data.
-    >>> f = AuthorForm(request.POST)
-
-    # Create, but don't save the new author instance.
-    >>> new_author = f.save(commit=False)
-
-    # Modify the author in some way.
-    >>> new_author.some_field = 'some_value'
-
-    # Save the new instance.
-    >>> new_author.save()
-
-    # Now, save the many-to-many data for the form.
-    >>> f.save_m2m()
-
-Calling ``save_m2m()`` is only required if you use ``save(commit=False)``.
-When you use a simple ``save()`` on a form, all data -- including
-many-to-many data -- is saved without the need for any additional method calls.
-For example::
-
-    # Create a form instance with POST data.
-    >>> f = AuthorForm(request.POST)
-
-    # Create and save the new author instance. There's no need to do anything else.
-    >>> new_author = f.save()
-
-Using an alternate base class
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you want to add custom methods to the form generated by
-``form_for_model()``, write a class that extends ``django.newforms.BaseForm``
-and contains your custom methods. Then, use the ``form`` argument to
-``form_for_model()`` to tell it to use your custom form as its base class.
-For example::
-
-    # Create the new base class.
-    >>> class MyBase(BaseForm):
-    ...     def my_method(self):
-    ...         # Do whatever the method does
-
-    # Create the form class with a different base class.
-    >>> ArticleForm = form_for_model(Article, form=MyBase)
-
-    # Instantiate the form.
-    >>> f = ArticleForm()
-
-    # Use the base class method.
-    >>> f.my_method()
-
-Using a subset of fields on the form
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-**New in Django development version**
-
-In some cases, you may not want all the model fields to appear on the generated
-form. There are two ways of telling ``form_for_model()`` to use only a subset
-of the model fields:
-
-    1. Set ``editable=False`` on the model field. As a result, *any* form
-       created from the model via ``form_for_model()`` will not include that
-       field.
-
-    2. Use the ``fields`` argument to ``form_for_model()``. This argument, if
-       given, should be a list of field names to include in the form.
-
-       For example, if you want a form for the ``Author`` model (defined above)
-       that includes only the ``name`` and ``title`` fields, you would specify
-       ``fields`` like this::
-
-           PartialArticleForm = form_for_model(Author, fields=('name', 'title'))
-
-.. note::
-
-    If you specify ``fields`` when creating a form with ``form_for_model()``,
-    then the fields that are *not* specified will not be set by the form's
-    ``save()`` method. Django will prevent any attempt to save an incomplete
-    model, so if the model does not allow the missing fields to be empty, and
-    does not provide a default value for the missing fields, any attempt to
-    ``save()`` a ``form_for_model`` with missing fields will fail. To avoid
-    this failure, you must use ``save(commit=False)`` and manually set any
-    extra required fields::
-
-        instance = form.save(commit=False)
-        instance.required_field = 'new value'
-        instance.save()
-
-    See the `section on saving forms`_ for more details on using
-    ``save(commit=False)``.
-
-.. _section on saving forms: `The save() method`_
-
-Overriding the default field types
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The default field types, as described in the "Field types" table above, are
-sensible defaults; if you have a ``DateField`` in your model, chances are you'd
-want that to be represented as a ``DateField`` in your form. But
-``form_for_model()`` gives you the flexibility of changing the form field type
-for a given model field. You do this by specifying a **formfield callback**.
-
-A formfield callback is a function that, when provided with a model field,
-returns a form field instance. When constructing a form, ``form_for_model()``
-asks the formfield callback to provide form field types.
-
-By default, ``form_for_model()`` calls the ``formfield()`` method on the model
-field::
-
-    def default_callback(field, **kwargs):
-        return field.formfield(**kwargs)
-
-The ``kwargs`` are any keyword arguments that might be passed to the form
-field, such as ``required=True`` or ``label='Foo'``.
-
-For example, if you wanted to use ``MyDateFormField`` for any ``DateField``
-field on the model, you could define the callback::
-
-    >>> def my_callback(field, **kwargs):
-    ...     if isinstance(field, models.DateField):
-    ...         return MyDateFormField(**kwargs)
-    ...     else:
-    ...         return field.formfield(**kwargs)
-
-    >>> ArticleForm = form_for_model(Article, formfield_callback=my_callback)
-
-Note that your callback needs to handle *all* possible model field types, not
-just the ones that you want to behave differently to the default. That's why
-this example has an ``else`` clause that implements the default behavior.
-
-.. warning::
-    The field that is passed into the ``formfield_callback`` function in
-    ``form_for_model()`` and ``form_for_instance`` is the field instance from
-    your model's class. You **must not** alter that object at all; treat it
-    as read-only!
-
-    If you make any alterations to that object, it will affect any future
-    users of the model class, because you will have changed the field object
-    used to construct the class. This is almost certainly what you don't want
-    to have happen.
-
-Finding the model associated with a form
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The model class that was used to construct the form is available
-using the ``_model`` property of the generated form::
-
-    >>> ArticleForm = form_for_model(Article)
-    >>> ArticleForm._model
-    <class 'myapp.models.Article'>
-
-``form_for_instance()``
------------------------
-
-``form_for_instance()`` is like ``form_for_model()``, but it takes a model
-instance instead of a model class::
-
-    # Create an Author.
-    >>> a = Author(name='Joe Smith', title='MR', birth_date=None)
-    >>> a.save()
-
-    # Create a form for this particular Author.
-    >>> AuthorForm = form_for_instance(a)
-
-    # Instantiate the form.
-    >>> f = AuthorForm()
-
-When a form created by ``form_for_instance()`` is created, the initial data
-values for the form fields are drawn from the instance. However, this data is
-not bound to the form. You will need to bind data to the form before the form
-can be saved.
-
-Unlike ``form_for_model()``, a choice field in form created by
-``form_for_instance()`` will not include the blank choice if the respective
-model field has ``blank=False``. The initial choice is drawn from the instance.
-
-When you call ``save()`` on a form created by ``form_for_instance()``,
-the database instance will be updated. As in ``form_for_model()``, ``save()``
-will raise ``ValueError`` if the data doesn't validate.
-
-``form_for_instance()`` has ``form``, ``fields`` and ``formfield_callback``
-arguments that behave the same way as they do for ``form_for_model()``.
-
-Let's modify the earlier `contact form`_ view example a little bit. Suppose we
-have a ``Message`` model that holds each contact submission. Something like::
-
-    class Message(models.Model):
-        subject = models.CharField(max_length=100)
-        message = models.TextField()
-        sender = models.EmailField()
-        cc_myself = models.BooleanField(required=False)
-
-You could use this model to create a form (using ``form_for_model()``). You
-could also use existing ``Message`` instances to create a form for editing
-messages. The earlier_ view can be changed slightly to accept the ``id`` value
-of an existing ``Message`` and present it for editing::
-
-    def contact_edit(request, msg_id):
-        # Create the form from the message id.
-        message = get_object_or_404(Message, id=msg_id)
-        ContactForm = form_for_instance(message)
-
-        if request.method == 'POST':
-            form = ContactForm(request.POST)
-            if form.is_valid():
-                form.save()
-                return HttpResponseRedirect('/url/on_success/')
-        else:
-            form = ContactForm()
-        return render_to_response('contact.html', {'form': form})
-
-Aside from how we create the ``ContactForm`` class here, the main point to
-note is that the form display in the ``GET`` branch of the function
-will use the values from the ``message`` instance as initial values for the
-form field.
-
-.. _contact form: `Simple view example`_
-.. _earlier: `Simple view example`_
-
-When should you use ``form_for_model()`` and ``form_for_instance()``?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The ``form_for_model()`` and ``form_for_instance()`` functions are meant to be
-shortcuts for the common case. If you want to create a form whose fields map to
-more than one model, or a form that contains fields that *aren't* on a model,
-you shouldn't use these shortcuts. Creating a ``Form`` class the "long" way
-isn't that difficult, after all.
+.. _ModelForms documentation: ../modelforms/
+.. _view the documentation: ../form_for_model/
 
 More coming soon
 ================
diff --git a/tests/modeltests/model_forms_new/__init__.py b/tests/modeltests/model_forms_new/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/modeltests/model_forms_new/models.py b/tests/modeltests/model_forms_new/models.py
new file mode 100644
index 0000000..bd611ed
--- /dev/null
+++ b/tests/modeltests/model_forms_new/models.py
@@ -0,0 +1,698 @@
+"""
+XX. Generating HTML forms from models
+
+This is mostly just a reworking of the form_for_model/form_for_instance tests
+to use ModelForm. As such, the text may not make sense in all cases, and the
+examples are probably a poor fit for the ModelForm syntax. In other words,
+most of these tests should be rewritten.
+"""
+
+from django.db import models
+
+ARTICLE_STATUS = (
+    (1, 'Draft'),
+    (2, 'Pending'),
+    (3, 'Live'),
+)
+
+class Category(models.Model):
+    name = models.CharField(max_length=20)
+    slug = models.SlugField(max_length=20)
+    url = models.CharField('The URL', max_length=40)
+
+    def __unicode__(self):
+        return self.name
+
+class Writer(models.Model):
+    name = models.CharField(max_length=50, help_text='Use both first and last names.')
+
+    def __unicode__(self):
+        return self.name
+
+class Article(models.Model):
+    headline = models.CharField(max_length=50)
+    slug = models.SlugField()
+    pub_date = models.DateField()
+    created = models.DateField(editable=False)
+    writer = models.ForeignKey(Writer)
+    article = models.TextField()
+    categories = models.ManyToManyField(Category, blank=True)
+    status = models.IntegerField(choices=ARTICLE_STATUS, blank=True, null=True)
+
+    def save(self):
+        import datetime
+        if not self.id:
+            self.created = datetime.date.today()
+        return super(Article, self).save()
+
+    def __unicode__(self):
+        return self.headline
+
+class PhoneNumber(models.Model):
+    phone = models.PhoneNumberField()
+    description = models.CharField(max_length=20)
+
+    def __unicode__(self):
+        return self.phone
+
+__test__ = {'API_TESTS': """
+>>> from django import newforms as forms
+>>> from django.newforms.models import ModelForm
+
+The bare bones, absolutely nothing custom, basic case.
+
+>>> class CategoryForm(ModelForm):
+...     class Meta:
+...         model = Category
+>>> CategoryForm.base_fields.keys()
+['name', 'slug', 'url']
+
+
+Extra fields.
+
+>>> class CategoryForm(ModelForm):
+...     some_extra_field = forms.BooleanField()
+...
+...     class Meta:
+...         model = Category
+
+>>> CategoryForm.base_fields.keys()
+['name', 'slug', 'url', 'some_extra_field']
+
+
+Replacing a field.
+
+>>> class CategoryForm(ModelForm):
+...     url = forms.BooleanField()
+...
+...     class Meta:
+...         model = Category
+
+>>> CategoryForm.base_fields['url'].__class__
+<class 'django.newforms.fields.BooleanField'>
+
+
+Using 'fields'.
+
+>>> class CategoryForm(ModelForm):
+...
+...     class Meta:
+...         model = Category
+...         fields = ['url']
+
+>>> CategoryForm.base_fields.keys()
+['url']
+
+
+Using 'exclude'
+
+>>> class CategoryForm(ModelForm):
+...
+...     class Meta:
+...         model = Category
+...         exclude = ['url']
+
+>>> CategoryForm.base_fields.keys()
+['name', 'slug']
+
+
+Using 'fields' *and* 'exclude'. Not sure why you'd want to do this, but uh,
+"be liberal in what you accept" and all.
+
+>>> class CategoryForm(ModelForm):
+...
+...     class Meta:
+...         model = Category
+...         fields = ['name', 'url']
+...         exclude = ['url']
+
+>>> CategoryForm.base_fields.keys()
+['name']
+
+Don't allow more than one 'model' defenition in the inheritance hierarchy.
+Technically, it would generate a valid form, but the fact that the resulting
+save method won't deal with multiple objects is likely to trip up people not
+familiar with the mechanics.
+
+>>> class CategoryForm(ModelForm):
+...     class Meta:
+...         model = Category
+
+>>> class BadForm(CategoryForm):
+...     class Meta:
+...         model = Article
+Traceback (most recent call last):
+...
+ImproperlyConfigured: BadForm defines more than one model.
+
+>>> class ArticleForm(ModelForm):
+...     class Meta:
+...         model = Article
+
+>>> class BadForm(ArticleForm, CategoryForm):
+...     pass
+Traceback (most recent call last):
+...
+ImproperlyConfigured: BadForm's base classes define more than one model.
+
+
+# Old form_for_x tests #######################################################
+
+>>> from django.newforms import ModelForm, CharField
+>>> import datetime
+
+>>> Category.objects.all()
+[]
+
+>>> class CategoryForm(ModelForm):
+...     class Meta:
+...         model = Category
+>>> f = CategoryForm(Category())
+>>> print f
+<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" maxlength="20" /></td></tr>
+<tr><th><label for="id_slug">Slug:</label></th><td><input id="id_slug" type="text" name="slug" maxlength="20" /></td></tr>
+<tr><th><label for="id_url">The URL:</label></th><td><input id="id_url" type="text" name="url" maxlength="40" /></td></tr>
+>>> print f.as_ul()
+<li><label for="id_name">Name:</label> <input id="id_name" type="text" name="name" maxlength="20" /></li>
+<li><label for="id_slug">Slug:</label> <input id="id_slug" type="text" name="slug" maxlength="20" /></li>
+<li><label for="id_url">The URL:</label> <input id="id_url" type="text" name="url" maxlength="40" /></li>
+>>> print f['name']
+<input id="id_name" type="text" name="name" maxlength="20" />
+
+>>> f = CategoryForm(Category(), auto_id=False)
+>>> print f.as_ul()
+<li>Name: <input type="text" name="name" maxlength="20" /></li>
+<li>Slug: <input type="text" name="slug" maxlength="20" /></li>
+<li>The URL: <input type="text" name="url" maxlength="40" /></li>
+
+>>> f = CategoryForm(Category(), {'name': 'Entertainment', 'slug': 'entertainment', 'url': 'entertainment'})
+>>> f.is_valid()
+True
+>>> f.cleaned_data
+{'url': u'entertainment', 'name': u'Entertainment', 'slug': u'entertainment'}
+>>> obj = f.save()
+>>> obj
+<Category: Entertainment>
+>>> Category.objects.all()
+[<Category: Entertainment>]
+
+>>> f = CategoryForm(Category(), {'name': "It's a test", 'slug': 'its-test', 'url': 'test'})
+>>> f.is_valid()
+True
+>>> f.cleaned_data
+{'url': u'test', 'name': u"It's a test", 'slug': u'its-test'}
+>>> obj = f.save()
+>>> obj
+<Category: It's a test>
+>>> Category.objects.order_by('name')
+[<Category: Entertainment>, <Category: It's a test>]
+
+If you call save() with commit=False, then it will return an object that
+hasn't yet been saved to the database. In this case, it's up to you to call
+save() on the resulting model instance.
+>>> f = CategoryForm(Category(), {'name': 'Third test', 'slug': 'third-test', 'url': 'third'})
+>>> f.is_valid()
+True
+>>> f.cleaned_data
+{'url': u'third', 'name': u'Third test', 'slug': u'third-test'}
+>>> obj = f.save(commit=False)
+>>> obj
+<Category: Third test>
+>>> Category.objects.order_by('name')
+[<Category: Entertainment>, <Category: It's a test>]
+>>> obj.save()
+>>> Category.objects.order_by('name')
+[<Category: Entertainment>, <Category: It's a test>, <Category: Third test>]
+
+If you call save() with invalid data, you'll get a ValueError.
+>>> f = CategoryForm(Category(), {'name': '', 'slug': '', 'url': 'foo'})
+>>> f.errors
+{'name': [u'This field is required.'], 'slug': [u'This field is required.']}
+>>> f.cleaned_data
+Traceback (most recent call last):
+...
+AttributeError: 'CategoryForm' object has no attribute 'cleaned_data'
+>>> f.save()
+Traceback (most recent call last):
+...
+ValueError: The Category could not be created because the data didn't validate.
+>>> f = CategoryForm(Category(), {'name': '', 'slug': '', 'url': 'foo'})
+>>> f.save()
+Traceback (most recent call last):
+...
+ValueError: The Category could not be created because the data didn't validate.
+
+Create a couple of Writers.
+>>> w = Writer(name='Mike Royko')
+>>> w.save()
+>>> w = Writer(name='Bob Woodward')
+>>> w.save()
+
+ManyToManyFields are represented by a MultipleChoiceField, ForeignKeys and any
+fields with the 'choices' attribute are represented by a ChoiceField.
+>>> class ArticleForm(ModelForm):
+...     class Meta:
+...         model = Article
+>>> f = ArticleForm(Article(), auto_id=False)
+>>> print f
+<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr>
+<tr><th>Slug:</th><td><input type="text" name="slug" maxlength="50" /></td></tr>
+<tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr>
+<tr><th>Writer:</th><td><select name="writer">
+<option value="" selected="selected">---------</option>
+<option value="1">Mike Royko</option>
+<option value="2">Bob Woodward</option>
+</select></td></tr>
+<tr><th>Article:</th><td><textarea rows="10" cols="40" name="article"></textarea></td></tr>
+<tr><th>Status:</th><td><select name="status">
+<option value="" selected="selected">---------</option>
+<option value="1">Draft</option>
+<option value="2">Pending</option>
+<option value="3">Live</option>
+</select></td></tr>
+<tr><th>Categories:</th><td><select multiple="multiple" name="categories">
+<option value="1">Entertainment</option>
+<option value="2">It&#39;s a test</option>
+<option value="3">Third test</option>
+</select><br /> Hold down "Control", or "Command" on a Mac, to select more than one.</td></tr>
+
+You can restrict a form to a subset of the complete list of fields
+by providing a 'fields' argument. If you try to save a
+model created with such a form, you need to ensure that the fields
+that are _not_ on the form have default values, or are allowed to have
+a value of None. If a field isn't specified on a form, the object created
+from the form can't provide a value for that field!
+>>> class PartialArticleForm(ModelForm):
+...     class Meta:
+...         model = Article
+...         fields = ('headline','pub_date')
+>>> f = PartialArticleForm(Article(), auto_id=False)
+>>> print f
+<tr><th>Headline:</th><td><input type="text" name="headline" maxlength="50" /></td></tr>
+<tr><th>Pub date:</th><td><input type="text" name="pub_date" /></td></tr>
+
+Use form_for_instance to create a Form from a model instance. The difference
+between this Form and one created via form_for_model is that the object's
+current values are inserted as 'initial' data in each Field.
+>>> w = Writer.objects.get(name='Mike Royko')
+>>> class RoykoForm(ModelForm):
+...     class Meta:
+...         model = Writer
+>>> f = RoykoForm(w, auto_id=False)
+>>> print f
+<tr><th>Name:</th><td><input type="text" name="name" value="Mike Royko" maxlength="50" /><br />Use both first and last names.</td></tr>
+
+>>> art = Article(headline='Test article', slug='test-article', pub_date=datetime.date(1988, 1, 4), writer=w, article='Hello.')
+>>> art.save()
+>>> art.id
+1
+>>> class TestArticleForm(ModelForm):
+...     class Meta:
+...         model = Article
+>>> f = TestArticleForm(art, auto_id=False)
+>>> print f.as_ul()
+<li>Headline: <input type="text" name="headline" value="Test article" maxlength="50" /></li>
+<li>Slug: <input type="text" name="slug" value="test-article" maxlength="50" /></li>
+<li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li>
+<li>Writer: <select name="writer">
+<option value="">---------</option>
+<option value="1" selected="selected">Mike Royko</option>
+<option value="2">Bob Woodward</option>
+</select></li>
+<li>Article: <textarea rows="10" cols="40" name="article">Hello.</textarea></li>
+<li>Status: <select name="status">
+<option value="" selected="selected">---------</option>
+<option value="1">Draft</option>
+<option value="2">Pending</option>
+<option value="3">Live</option>
+</select></li>
+<li>Categories: <select multiple="multiple" name="categories">
+<option value="1">Entertainment</option>
+<option value="2">It&#39;s a test</option>
+<option value="3">Third test</option>
+</select>  Hold down "Control", or "Command" on a Mac, to select more than one.</li>
+>>> f = TestArticleForm(art, {'headline': u'Test headline', 'slug': 'test-headline', 'pub_date': u'1984-02-06', 'writer': u'1', 'article': 'Hello.'})
+>>> f.is_valid()
+True
+>>> test_art = f.save()
+>>> test_art.id
+1
+>>> test_art = Article.objects.get(id=1)
+>>> test_art.headline
+u'Test headline'
+
+You can create a form over a subset of the available fields
+by specifying a 'fields' argument to form_for_instance.
+>>> class PartialArticleForm(ModelForm):
+...     class Meta:
+...         model = Article
+...         fields=('headline', 'slug', 'pub_date')
+>>> f = PartialArticleForm(art, {'headline': u'New headline', 'slug': 'new-headline', 'pub_date': u'1988-01-04'}, auto_id=False)
+>>> print f.as_ul()
+<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li>
+<li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li>
+<li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li>
+>>> f.is_valid()
+True
+>>> new_art = f.save()
+>>> new_art.id
+1
+>>> new_art = Article.objects.get(id=1)
+>>> new_art.headline
+u'New headline'
+
+Add some categories and test the many-to-many form output.
+>>> new_art.categories.all()
+[]
+>>> new_art.categories.add(Category.objects.get(name='Entertainment'))
+>>> new_art.categories.all()
+[<Category: Entertainment>]
+>>> class TestArticleForm(ModelForm):
+...     class Meta:
+...         model = Article
+>>> f = TestArticleForm(new_art, auto_id=False)
+>>> print f.as_ul()
+<li>Headline: <input type="text" name="headline" value="New headline" maxlength="50" /></li>
+<li>Slug: <input type="text" name="slug" value="new-headline" maxlength="50" /></li>
+<li>Pub date: <input type="text" name="pub_date" value="1988-01-04" /></li>
+<li>Writer: <select name="writer">
+<option value="">---------</option>
+<option value="1" selected="selected">Mike Royko</option>
+<option value="2">Bob Woodward</option>
+</select></li>
+<li>Article: <textarea rows="10" cols="40" name="article">Hello.</textarea></li>
+<li>Status: <select name="status">
+<option value="" selected="selected">---------</option>
+<option value="1">Draft</option>
+<option value="2">Pending</option>
+<option value="3">Live</option>
+</select></li>
+<li>Categories: <select multiple="multiple" name="categories">
+<option value="1" selected="selected">Entertainment</option>
+<option value="2">It&#39;s a test</option>
+<option value="3">Third test</option>
+</select>  Hold down "Control", or "Command" on a Mac, to select more than one.</li>
+
+>>> f = TestArticleForm(new_art, {'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04',
+...     'writer': u'1', 'article': u'Hello.', 'categories': [u'1', u'2']})
+>>> new_art = f.save()
+>>> new_art.id
+1
+>>> new_art = Article.objects.get(id=1)
+>>> new_art.categories.order_by('name')
+[<Category: Entertainment>, <Category: It's a test>]
+
+Now, submit form data with no categories. This deletes the existing categories.
+>>> f = TestArticleForm(new_art, {'headline': u'New headline', 'slug': u'new-headline', 'pub_date': u'1988-01-04',
+...     'writer': u'1', 'article': u'Hello.'})
+>>> new_art = f.save()
+>>> new_art.id
+1
+>>> new_art = Article.objects.get(id=1)
+>>> new_art.categories.all()
+[]
+
+Create a new article, with categories, via the form.
+>>> class ArticleForm(ModelForm):
+...     class Meta:
+...         model = Article
+>>> f = ArticleForm(Article(), {'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01',
+...     'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']})
+>>> new_art = f.save()
+>>> new_art.id
+2
+>>> new_art = Article.objects.get(id=2)
+>>> new_art.categories.order_by('name')
+[<Category: Entertainment>, <Category: It's a test>]
+
+Create a new article, with no categories, via the form.
+>>> class ArticleForm(ModelForm):
+...     class Meta:
+...         model = Article
+>>> f = ArticleForm(Article(), {'headline': u'The walrus was Paul', 'slug': u'walrus-was-paul', 'pub_date': u'1967-11-01',
+...     'writer': u'1', 'article': u'Test.'})
+>>> new_art = f.save()
+>>> new_art.id
+3
+>>> new_art = Article.objects.get(id=3)
+>>> new_art.categories.all()
+[]
+
+Create a new article, with categories, via the form, but use commit=False.
+The m2m data won't be saved until save_m2m() is invoked on the form.
+>>> class ArticleForm(ModelForm):
+...     class Meta:
+...         model = Article
+>>> f = ArticleForm(Article(), {'headline': u'The walrus was Paul', 'slug': 'walrus-was-paul', 'pub_date': u'1967-11-01',
+...     'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']})
+>>> new_art = f.save(commit=False)
+
+# Manually save the instance
+>>> new_art.save()
+>>> new_art.id
+4
+
+# The instance doesn't have m2m data yet
+>>> new_art = Article.objects.get(id=4)
+>>> new_art.categories.all()
+[]
+
+# Save the m2m data on the form
+>>> f.save_m2m()
+>>> new_art.categories.order_by('name')
+[<Category: Entertainment>, <Category: It's a test>]
+
+Here, we define a custom ModelForm. Because it happens to have the same fields as
+the Category model, we can just call the form's save() to apply its changes to an
+existing Category instance.
+>>> class ShortCategory(ModelForm):
+...     name = CharField(max_length=5)
+...     slug = CharField(max_length=5)
+...     url = CharField(max_length=3)
+>>> cat = Category.objects.get(name='Third test')
+>>> cat
+<Category: Third test>
+>>> cat.id
+3
+>>> form = ShortCategory(cat, {'name': 'Third', 'slug': 'third', 'url': '3rd'})
+>>> form.save()
+<Category: Third>
+>>> Category.objects.get(id=3)
+<Category: Third>
+
+Here, we demonstrate that choices for a ForeignKey ChoiceField are determined
+at runtime, based on the data in the database when the form is displayed, not
+the data in the database when the form is instantiated.
+>>> class ArticleForm(ModelForm):
+...     class Meta:
+...         model = Article
+>>> f = ArticleForm(Article(), auto_id=False)
+>>> print f.as_ul()
+<li>Headline: <input type="text" name="headline" maxlength="50" /></li>
+<li>Slug: <input type="text" name="slug" maxlength="50" /></li>
+<li>Pub date: <input type="text" name="pub_date" /></li>
+<li>Writer: <select name="writer">
+<option value="" selected="selected">---------</option>
+<option value="1">Mike Royko</option>
+<option value="2">Bob Woodward</option>
+</select></li>
+<li>Article: <textarea rows="10" cols="40" name="article"></textarea></li>
+<li>Status: <select name="status">
+<option value="" selected="selected">---------</option>
+<option value="1">Draft</option>
+<option value="2">Pending</option>
+<option value="3">Live</option>
+</select></li>
+<li>Categories: <select multiple="multiple" name="categories">
+<option value="1">Entertainment</option>
+<option value="2">It&#39;s a test</option>
+<option value="3">Third</option>
+</select>  Hold down "Control", or "Command" on a Mac, to select more than one.</li>
+>>> Category.objects.create(name='Fourth', url='4th')
+<Category: Fourth>
+>>> Writer.objects.create(name='Carl Bernstein')
+<Writer: Carl Bernstein>
+>>> print f.as_ul()
+<li>Headline: <input type="text" name="headline" maxlength="50" /></li>
+<li>Slug: <input type="text" name="slug" maxlength="50" /></li>
+<li>Pub date: <input type="text" name="pub_date" /></li>
+<li>Writer: <select name="writer">
+<option value="" selected="selected">---------</option>
+<option value="1">Mike Royko</option>
+<option value="2">Bob Woodward</option>
+<option value="3">Carl Bernstein</option>
+</select></li>
+<li>Article: <textarea rows="10" cols="40" name="article"></textarea></li>
+<li>Status: <select name="status">
+<option value="" selected="selected">---------</option>
+<option value="1">Draft</option>
+<option value="2">Pending</option>
+<option value="3">Live</option>
+</select></li>
+<li>Categories: <select multiple="multiple" name="categories">
+<option value="1">Entertainment</option>
+<option value="2">It&#39;s a test</option>
+<option value="3">Third</option>
+<option value="4">Fourth</option>
+</select>  Hold down "Control", or "Command" on a Mac, to select more than one.</li>
+
+# ModelChoiceField ############################################################
+
+>>> from django.newforms import ModelChoiceField, ModelMultipleChoiceField
+
+>>> f = ModelChoiceField(Category.objects.all())
+>>> list(f.choices)
+[(u'', u'---------'), (1, u'Entertainment'), (2, u"It's a test"), (3, u'Third'), (4, u'Fourth')]
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(0)
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
+>>> f.clean(3)
+<Category: Third>
+>>> f.clean(2)
+<Category: It's a test>
+
+# Add a Category object *after* the ModelChoiceField has already been
+# instantiated. This proves clean() checks the database during clean() rather
+# than caching it at time of instantiation.
+>>> Category.objects.create(name='Fifth', url='5th')
+<Category: Fifth>
+>>> f.clean(5)
+<Category: Fifth>
+
+# Delete a Category object *after* the ModelChoiceField has already been
+# instantiated. This proves clean() checks the database during clean() rather
+# than caching it at time of instantiation.
+>>> Category.objects.get(url='5th').delete()
+>>> f.clean(5)
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
+
+>>> f = ModelChoiceField(Category.objects.filter(pk=1), required=False)
+>>> print f.clean('')
+None
+>>> f.clean('')
+>>> f.clean('1')
+<Category: Entertainment>
+>>> f.clean('100')
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
+
+# queryset can be changed after the field is created.
+>>> f.queryset = Category.objects.exclude(name='Fourth')
+>>> list(f.choices)
+[(u'', u'---------'), (1, u'Entertainment'), (2, u"It's a test"), (3, u'Third')]
+>>> f.clean(3)
+<Category: Third>
+>>> f.clean(4)
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
+
+
+# ModelMultipleChoiceField ####################################################
+
+>>> f = ModelMultipleChoiceField(Category.objects.all())
+>>> list(f.choices)
+[(1, u'Entertainment'), (2, u"It's a test"), (3, u'Third'), (4, u'Fourth')]
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean([])
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean([1])
+[<Category: Entertainment>]
+>>> f.clean([2])
+[<Category: It's a test>]
+>>> f.clean(['1'])
+[<Category: Entertainment>]
+>>> f.clean(['1', '2'])
+[<Category: Entertainment>, <Category: It's a test>]
+>>> f.clean([1, '2'])
+[<Category: Entertainment>, <Category: It's a test>]
+>>> f.clean((1, '2'))
+[<Category: Entertainment>, <Category: It's a test>]
+>>> f.clean(['100'])
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. 100 is not one of the available choices.']
+>>> f.clean('hello')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a list of values.']
+
+# Add a Category object *after* the ModelMultipleChoiceField has already been
+# instantiated. This proves clean() checks the database during clean() rather
+# than caching it at time of instantiation.
+>>> Category.objects.create(id=6, name='Sixth', url='6th')
+<Category: Sixth>
+>>> f.clean([6])
+[<Category: Sixth>]
+
+# Delete a Category object *after* the ModelMultipleChoiceField has already been
+# instantiated. This proves clean() checks the database during clean() rather
+# than caching it at time of instantiation.
+>>> Category.objects.get(url='6th').delete()
+>>> f.clean([6])
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. 6 is not one of the available choices.']
+
+>>> f = ModelMultipleChoiceField(Category.objects.all(), required=False)
+>>> f.clean([])
+[]
+>>> f.clean(())
+[]
+>>> f.clean(['10'])
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. 10 is not one of the available choices.']
+>>> f.clean(['3', '10'])
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. 10 is not one of the available choices.']
+>>> f.clean(['1', '10'])
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. 10 is not one of the available choices.']
+
+# queryset can be changed after the field is created.
+>>> f.queryset = Category.objects.exclude(name='Fourth')
+>>> list(f.choices)
+[(1, u'Entertainment'), (2, u"It's a test"), (3, u'Third')]
+>>> f.clean([3])
+[<Category: Third>]
+>>> f.clean([4])
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. 4 is not one of the available choices.']
+>>> f.clean(['3', '4'])
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. 4 is not one of the available choices.']
+
+
+# PhoneNumberField ############################################################
+
+>>> class PhoneNumberForm(ModelForm):
+...     class Meta:
+...         model = PhoneNumber
+>>> f = PhoneNumberForm(PhoneNumber(), {'phone': '(312) 555-1212', 'description': 'Assistance'})
+>>> f.is_valid()
+True
+>>> f.cleaned_data
+{'phone': u'312-555-1212', 'description': u'Assistance'}
+"""}
