summaryrefslogtreecommitdiff
path: root/parts/django/docs/topics/forms
diff options
context:
space:
mode:
authorNishanth Amuluru2011-01-08 11:20:57 +0530
committerNishanth Amuluru2011-01-08 11:20:57 +0530
commit65411d01d448ff0cd4abd14eee14cf60b5f8fc20 (patch)
treeb4c404363c4c63a61d6e2f8bd26c5b057c1fb09d /parts/django/docs/topics/forms
parent2e35094d43b4cc6974172e1febf76abb50f086ec (diff)
downloadpytask-65411d01d448ff0cd4abd14eee14cf60b5f8fc20.tar.gz
pytask-65411d01d448ff0cd4abd14eee14cf60b5f8fc20.tar.bz2
pytask-65411d01d448ff0cd4abd14eee14cf60b5f8fc20.zip
Added buildout stuff and made changes accordingly
--HG-- rename : profile/management/__init__.py => eggs/djangorecipe-0.20-py2.6.egg/EGG-INFO/dependency_links.txt rename : profile/management/__init__.py => eggs/djangorecipe-0.20-py2.6.egg/EGG-INFO/not-zip-safe rename : profile/management/__init__.py => eggs/infrae.subversion-1.4.5-py2.6.egg/EGG-INFO/dependency_links.txt rename : profile/management/__init__.py => eggs/infrae.subversion-1.4.5-py2.6.egg/EGG-INFO/not-zip-safe rename : profile/management/__init__.py => eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/EGG-INFO/dependency_links.txt rename : profile/management/__init__.py => eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/EGG-INFO/not-zip-safe rename : profile/management/__init__.py => eggs/py-1.4.0-py2.6.egg/EGG-INFO/dependency_links.txt rename : profile/management/__init__.py => eggs/py-1.4.0-py2.6.egg/EGG-INFO/not-zip-safe rename : profile/management/__init__.py => eggs/zc.buildout-1.5.2-py2.6.egg/EGG-INFO/dependency_links.txt rename : profile/management/__init__.py => eggs/zc.buildout-1.5.2-py2.6.egg/EGG-INFO/not-zip-safe rename : profile/management/__init__.py => eggs/zc.recipe.egg-1.3.2-py2.6.egg/EGG-INFO/dependency_links.txt rename : profile/management/__init__.py => eggs/zc.recipe.egg-1.3.2-py2.6.egg/EGG-INFO/not-zip-safe rename : profile/management/__init__.py => parts/django/Django.egg-info/dependency_links.txt rename : taskapp/models.py => parts/django/django/conf/app_template/models.py rename : taskapp/tests.py => parts/django/django/conf/app_template/tests.py rename : taskapp/views.py => parts/django/django/conf/app_template/views.py rename : taskapp/views.py => parts/django/django/contrib/gis/tests/geo3d/views.py rename : profile/management/__init__.py => parts/django/tests/modeltests/delete/__init__.py rename : profile/management/__init__.py => parts/django/tests/modeltests/files/__init__.py rename : profile/management/__init__.py => parts/django/tests/modeltests/invalid_models/__init__.py rename : profile/management/__init__.py => parts/django/tests/modeltests/m2m_signals/__init__.py rename : profile/management/__init__.py => parts/django/tests/modeltests/model_package/__init__.py rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/__init__.py rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/management/__init__.py rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/management/commands/__init__.py rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/models.py rename : profile/management/__init__.py => parts/django/tests/regressiontests/delete_regress/__init__.py rename : profile/management/__init__.py => parts/django/tests/regressiontests/file_storage/__init__.py rename : profile/management/__init__.py => parts/django/tests/regressiontests/max_lengths/__init__.py rename : profile/forms.py => pytask/profile/forms.py rename : profile/management/__init__.py => pytask/profile/management/__init__.py rename : profile/management/commands/seed_db.py => pytask/profile/management/commands/seed_db.py rename : profile/models.py => pytask/profile/models.py rename : profile/templatetags/user_tags.py => pytask/profile/templatetags/user_tags.py rename : taskapp/tests.py => pytask/profile/tests.py rename : profile/urls.py => pytask/profile/urls.py rename : profile/utils.py => pytask/profile/utils.py rename : profile/views.py => pytask/profile/views.py rename : static/css/base.css => pytask/static/css/base.css rename : taskapp/tests.py => pytask/taskapp/tests.py rename : taskapp/views.py => pytask/taskapp/views.py rename : templates/base.html => pytask/templates/base.html rename : templates/profile/browse_notifications.html => pytask/templates/profile/browse_notifications.html rename : templates/profile/edit.html => pytask/templates/profile/edit.html rename : templates/profile/view.html => pytask/templates/profile/view.html rename : templates/profile/view_notification.html => pytask/templates/profile/view_notification.html rename : templates/registration/activate.html => pytask/templates/registration/activate.html rename : templates/registration/activation_email.txt => pytask/templates/registration/activation_email.txt rename : templates/registration/activation_email_subject.txt => pytask/templates/registration/activation_email_subject.txt rename : templates/registration/logged_out.html => pytask/templates/registration/logged_out.html rename : templates/registration/login.html => pytask/templates/registration/login.html rename : templates/registration/logout.html => pytask/templates/registration/logout.html rename : templates/registration/password_change_done.html => pytask/templates/registration/password_change_done.html rename : templates/registration/password_change_form.html => pytask/templates/registration/password_change_form.html rename : templates/registration/password_reset_complete.html => pytask/templates/registration/password_reset_complete.html rename : templates/registration/password_reset_confirm.html => pytask/templates/registration/password_reset_confirm.html rename : templates/registration/password_reset_done.html => pytask/templates/registration/password_reset_done.html rename : templates/registration/password_reset_email.html => pytask/templates/registration/password_reset_email.html rename : templates/registration/password_reset_form.html => pytask/templates/registration/password_reset_form.html rename : templates/registration/registration_complete.html => pytask/templates/registration/registration_complete.html rename : templates/registration/registration_form.html => pytask/templates/registration/registration_form.html rename : utils.py => pytask/utils.py
Diffstat (limited to 'parts/django/docs/topics/forms')
-rw-r--r--parts/django/docs/topics/forms/formsets.txt440
-rw-r--r--parts/django/docs/topics/forms/index.txt402
-rw-r--r--parts/django/docs/topics/forms/media.txt309
-rw-r--r--parts/django/docs/topics/forms/modelforms.txt885
4 files changed, 2036 insertions, 0 deletions
diff --git a/parts/django/docs/topics/forms/formsets.txt b/parts/django/docs/topics/forms/formsets.txt
new file mode 100644
index 0000000..72296bc
--- /dev/null
+++ b/parts/django/docs/topics/forms/formsets.txt
@@ -0,0 +1,440 @@
+.. _formsets:
+
+Formsets
+========
+
+A formset is a layer of abstraction to working with multiple forms on the same
+page. It can be best compared to a data grid. Let's say you have the following
+form::
+
+ >>> from django import forms
+ >>> class ArticleForm(forms.Form):
+ ... title = forms.CharField()
+ ... pub_date = forms.DateField()
+
+You might want to allow the user to create several articles at once. To create
+a formset out of an ``ArticleForm`` you would do::
+
+ >>> from django.forms.formsets import formset_factory
+ >>> ArticleFormSet = formset_factory(ArticleForm)
+
+You now have created a formset named ``ArticleFormSet``. The formset gives you
+the ability to iterate over the forms in the formset and display them as you
+would with a regular form::
+
+ >>> formset = ArticleFormSet()
+ >>> for form in formset.forms:
+ ... print form.as_table()
+ <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
+ <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>
+
+As you can see it only displayed one empty form. The number of empty forms
+that is displayed is controlled by the ``extra`` parameter. By default,
+``formset_factory`` defines one extra form; the following example will
+display two blank forms::
+
+ >>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
+
+Using initial data with a formset
+---------------------------------
+
+Initial data is what drives the main usability of a formset. As shown above
+you can define the number of extra forms. What this means is that you are
+telling the formset how many additional forms to show in addition to the
+number of forms it generates from the initial data. Lets take a look at an
+example::
+
+ >>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
+ >>> formset = ArticleFormSet(initial=[
+ ... {'title': u'Django is now open source',
+ ... 'pub_date': datetime.date.today()},
+ ... ])
+
+ >>> for form in formset.forms:
+ ... print form.as_table()
+ <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Django is now open source" id="id_form-0-title" /></td></tr>
+ <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-12" id="id_form-0-pub_date" /></td></tr>
+ <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" id="id_form-1-title" /></td></tr>
+ <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" id="id_form-1-pub_date" /></td></tr>
+ <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
+ <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>
+
+There are now a total of three forms showing above. One for the initial data
+that was passed in and two extra forms. Also note that we are passing in a
+list of dictionaries as the initial data.
+
+.. seealso::
+
+ :ref:`Creating formsets from models with model formsets <model-formsets>`.
+
+.. _formsets-max-num:
+
+Limiting the maximum number of forms
+------------------------------------
+
+The ``max_num`` parameter to ``formset_factory`` gives you the ability to
+limit the maximum number of empty forms the formset will display::
+
+ >>> ArticleFormSet = formset_factory(ArticleForm, extra=2, max_num=1)
+ >>> formset = ArticleFormset()
+ >>> for form in formset.forms:
+ ... print form.as_table()
+ <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
+ <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>
+
+.. versionchanged:: 1.2
+
+If the value of ``max_num`` is greater than the number of existing
+objects, up to ``extra`` additional blank forms will be added to the formset,
+so long as the total number of forms does not exceed ``max_num``.
+
+A ``max_num`` value of ``None`` (the default) puts no limit on the number of
+forms displayed. Please note that the default value of ``max_num`` was changed
+from ``0`` to ``None`` in version 1.2 to allow ``0`` as a valid value.
+
+Formset validation
+------------------
+
+Validation with a formset is almost identical to a regular ``Form``. There is
+an ``is_valid`` method on the formset to provide a convenient way to validate
+all forms in the formset::
+
+ >>> ArticleFormSet = formset_factory(ArticleForm)
+ >>> formset = ArticleFormSet({})
+ >>> formset.is_valid()
+ True
+
+We passed in no data to the formset which is resulting in a valid form. The
+formset is smart enough to ignore extra forms that were not changed. If we
+provide an invalid article::
+
+ >>> data = {
+ ... 'form-TOTAL_FORMS': u'2',
+ ... 'form-INITIAL_FORMS': u'0',
+ ... 'form-MAX_NUM_FORMS': u'',
+ ... 'form-0-title': u'Test',
+ ... 'form-0-pub_date': u'16 June 1904',
+ ... 'form-1-title': u'Test',
+ ... 'form-1-pub_date': u'', # <-- this date is missing but required
+ ... }
+ >>> formset = ArticleFormSet(data)
+ >>> formset.is_valid()
+ False
+ >>> formset.errors
+ [{}, {'pub_date': [u'This field is required.']}]
+
+As we can see, ``formset.errors`` is a list whose entries correspond to the
+forms in the formset. Validation was performed for each of the two forms, and
+the expected error message appears for the second item.
+
+.. _understanding-the-managementform:
+
+Understanding the ManagementForm
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You may have noticed the additional data (``form-TOTAL_FORMS``,
+``form-INITIAL_FORMS`` and ``form-MAX_NUM_FORMS``) that was required
+in the formset's data above. This data is required for the
+``ManagementForm``. This form is used by the formset to manage the
+collection of forms contained in the formset. If you don't provide
+this management data, an exception will be raised::
+
+ >>> data = {
+ ... 'form-0-title': u'Test',
+ ... 'form-0-pub_date': u'',
+ ... }
+ >>> formset = ArticleFormSet(data)
+ Traceback (most recent call last):
+ ...
+ django.forms.util.ValidationError: [u'ManagementForm data is missing or has been tampered with']
+
+It is used to keep track of how many form instances are being displayed. If
+you are adding new forms via JavaScript, you should increment the count fields
+in this form as well.
+
+The management form is available as an attribute of the formset
+itself. When rendering a formset in a template, you can include all
+the management data by rendering ``{{ my_formset.management_form }}``
+(substituting the name of your formset as appropriate).
+
+.. versionadded:: 1.1
+
+``total_form_count`` and ``initial_form_count``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``BaseFormSet`` has a couple of methods that are closely related to the
+``ManagementForm``, ``total_form_count`` and ``initial_form_count``.
+
+``total_form_count`` returns the total number of forms in this formset.
+``initial_form_count`` returns the number of forms in the formset that were
+pre-filled, and is also used to determine how many forms are required. You
+will probably never need to override either of these methods, so please be
+sure you understand what they do before doing so.
+
+.. versionadded:: 1.2
+
+``empty_form``
+~~~~~~~~~~~~~~
+
+``BaseFormSet`` provides an additional attribute ``empty_form`` which returns
+a form instance with a prefix of ``__prefix__`` for easier use in dynamic
+forms with JavaScript.
+
+Custom formset validation
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A formset has a ``clean`` method similar to the one on a ``Form`` class. This
+is where you define your own validation that works at the formset level::
+
+ >>> from django.forms.formsets import BaseFormSet
+
+ >>> class BaseArticleFormSet(BaseFormSet):
+ ... def clean(self):
+ ... """Checks that no two articles have the same title."""
+ ... if any(self.errors):
+ ... # Don't bother validating the formset unless each form is valid on its own
+ ... return
+ ... titles = []
+ ... for i in range(0, self.total_form_count()):
+ ... form = self.forms[i]
+ ... title = form.cleaned_data['title']
+ ... if title in titles:
+ ... raise forms.ValidationError, "Articles in a set must have distinct titles."
+ ... titles.append(title)
+
+ >>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet)
+ >>> data = {
+ ... 'form-TOTAL_FORMS': u'2',
+ ... 'form-INITIAL_FORMS': u'0',
+ ... 'form-MAX_NUM_FORMS': u'',
+ ... 'form-0-title': u'Test',
+ ... 'form-0-pub_date': u'16 June 1904',
+ ... 'form-1-title': u'Test',
+ ... 'form-1-pub_date': u'23 June 1912',
+ ... }
+ >>> formset = ArticleFormSet(data)
+ >>> formset.is_valid()
+ False
+ >>> formset.errors
+ [{}, {}]
+ >>> formset.non_form_errors()
+ [u'Articles in a set must have distinct titles.']
+
+The formset ``clean`` method is called after all the ``Form.clean`` methods
+have been called. The errors will be found using the ``non_form_errors()``
+method on the formset.
+
+Dealing with ordering and deletion of forms
+-------------------------------------------
+
+Common use cases with a formset is dealing with ordering and deletion of the
+form instances. This has been dealt with for you. The ``formset_factory``
+provides two optional parameters ``can_order`` and ``can_delete`` that will do
+the extra work of adding the extra fields and providing simpler ways of
+getting to that data.
+
+``can_order``
+~~~~~~~~~~~~~
+
+Default: ``False``
+
+Lets create a formset with the ability to order::
+
+ >>> ArticleFormSet = formset_factory(ArticleForm, can_order=True)
+ >>> formset = ArticleFormSet(initial=[
+ ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
+ ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
+ ... ])
+ >>> for form in formset.forms:
+ ... print form.as_table()
+ <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title" /></td></tr>
+ <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date" /></td></tr>
+ <tr><th><label for="id_form-0-ORDER">Order:</label></th><td><input type="text" name="form-0-ORDER" value="1" id="id_form-0-ORDER" /></td></tr>
+ <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title" /></td></tr>
+ <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date" /></td></tr>
+ <tr><th><label for="id_form-1-ORDER">Order:</label></th><td><input type="text" name="form-1-ORDER" value="2" id="id_form-1-ORDER" /></td></tr>
+ <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
+ <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>
+ <tr><th><label for="id_form-2-ORDER">Order:</label></th><td><input type="text" name="form-2-ORDER" id="id_form-2-ORDER" /></td></tr>
+
+This adds an additional field to each form. This new field is named ``ORDER``
+and is an ``forms.IntegerField``. For the forms that came from the initial
+data it automatically assigned them a numeric value. Lets look at what will
+happen when the user changes these values::
+
+ >>> data = {
+ ... 'form-TOTAL_FORMS': u'3',
+ ... 'form-INITIAL_FORMS': u'2',
+ ... 'form-MAX_NUM_FORMS': u'',
+ ... 'form-0-title': u'Article #1',
+ ... 'form-0-pub_date': u'2008-05-10',
+ ... 'form-0-ORDER': u'2',
+ ... 'form-1-title': u'Article #2',
+ ... 'form-1-pub_date': u'2008-05-11',
+ ... 'form-1-ORDER': u'1',
+ ... 'form-2-title': u'Article #3',
+ ... 'form-2-pub_date': u'2008-05-01',
+ ... 'form-2-ORDER': u'0',
+ ... }
+
+ >>> formset = ArticleFormSet(data, initial=[
+ ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
+ ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
+ ... ])
+ >>> formset.is_valid()
+ True
+ >>> for form in formset.ordered_forms:
+ ... print form.cleaned_data
+ {'pub_date': datetime.date(2008, 5, 1), 'ORDER': 0, 'title': u'Article #3'}
+ {'pub_date': datetime.date(2008, 5, 11), 'ORDER': 1, 'title': u'Article #2'}
+ {'pub_date': datetime.date(2008, 5, 10), 'ORDER': 2, 'title': u'Article #1'}
+
+``can_delete``
+~~~~~~~~~~~~~~
+
+Default: ``False``
+
+Lets create a formset with the ability to delete::
+
+ >>> ArticleFormSet = formset_factory(ArticleForm, can_delete=True)
+ >>> formset = ArticleFormSet(initial=[
+ ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
+ ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
+ ... ])
+ >>> for form in formset.forms:
+ .... print form.as_table()
+ <input type="hidden" name="form-TOTAL_FORMS" value="3" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="2" id="id_form-INITIAL_FORMS" /><input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS" />
+ <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title" /></td></tr>
+ <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date" /></td></tr>
+ <tr><th><label for="id_form-0-DELETE">Delete:</label></th><td><input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE" /></td></tr>
+ <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title" /></td></tr>
+ <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date" /></td></tr>
+ <tr><th><label for="id_form-1-DELETE">Delete:</label></th><td><input type="checkbox" name="form-1-DELETE" id="id_form-1-DELETE" /></td></tr>
+ <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
+ <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>
+ <tr><th><label for="id_form-2-DELETE">Delete:</label></th><td><input type="checkbox" name="form-2-DELETE" id="id_form-2-DELETE" /></td></tr>
+
+Similar to ``can_order`` this adds a new field to each form named ``DELETE``
+and is a ``forms.BooleanField``. When data comes through marking any of the
+delete fields you can access them with ``deleted_forms``::
+
+ >>> data = {
+ ... 'form-TOTAL_FORMS': u'3',
+ ... 'form-INITIAL_FORMS': u'2',
+ ... 'form-MAX_NUM_FORMS': u'',
+ ... 'form-0-title': u'Article #1',
+ ... 'form-0-pub_date': u'2008-05-10',
+ ... 'form-0-DELETE': u'on',
+ ... 'form-1-title': u'Article #2',
+ ... 'form-1-pub_date': u'2008-05-11',
+ ... 'form-1-DELETE': u'',
+ ... 'form-2-title': u'',
+ ... 'form-2-pub_date': u'',
+ ... 'form-2-DELETE': u'',
+ ... }
+
+ >>> formset = ArticleFormSet(data, initial=[
+ ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
+ ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
+ ... ])
+ >>> [form.cleaned_data for form in formset.deleted_forms]
+ [{'DELETE': True, 'pub_date': datetime.date(2008, 5, 10), 'title': u'Article #1'}]
+
+Adding additional fields to a formset
+-------------------------------------
+
+If you need to add additional fields to the formset this can be easily
+accomplished. The formset base class provides an ``add_fields`` method. You
+can simply override this method to add your own fields or even redefine the
+default fields/attributes of the order and deletion fields::
+
+ >>> class BaseArticleFormSet(BaseFormSet):
+ ... def add_fields(self, form, index):
+ ... super(BaseArticleFormSet, self).add_fields(form, index)
+ ... form.fields["my_field"] = forms.CharField()
+
+ >>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet)
+ >>> formset = ArticleFormSet()
+ >>> for form in formset.forms:
+ ... print form.as_table()
+ <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
+ <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>
+ <tr><th><label for="id_form-0-my_field">My field:</label></th><td><input type="text" name="form-0-my_field" id="id_form-0-my_field" /></td></tr>
+
+Using a formset in views and templates
+--------------------------------------
+
+Using a formset inside a view is as easy as using a regular ``Form`` class.
+The only thing you will want to be aware of is making sure to use the
+management form inside the template. Let's look at a sample view:
+
+.. code-block:: python
+
+ def manage_articles(request):
+ ArticleFormSet = formset_factory(ArticleForm)
+ if request.method == 'POST':
+ formset = ArticleFormSet(request.POST, request.FILES)
+ if formset.is_valid():
+ # do something with the formset.cleaned_data
+ pass
+ else:
+ formset = ArticleFormSet()
+ return render_to_response('manage_articles.html', {'formset': formset})
+
+The ``manage_articles.html`` template might look like this:
+
+.. code-block:: html+django
+
+ <form method="post" action="">
+ {{ formset.management_form }}
+ <table>
+ {% for form in formset.forms %}
+ {{ form }}
+ {% endfor %}
+ </table>
+ </form>
+
+However the above can be slightly shortcutted and let the formset itself deal
+with the management form:
+
+.. code-block:: html+django
+
+ <form method="post" action="">
+ <table>
+ {{ formset }}
+ </table>
+ </form>
+
+The above ends up calling the ``as_table`` method on the formset class.
+
+Using more than one formset in a view
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You are able to use more than one formset in a view if you like. Formsets
+borrow much of its behavior from forms. With that said you are able to use
+``prefix`` to prefix formset form field names with a given value to allow
+more than one formset to be sent to a view without name clashing. Lets take
+a look at how this might be accomplished:
+
+.. code-block:: python
+
+ def manage_articles(request):
+ ArticleFormSet = formset_factory(ArticleForm)
+ BookFormSet = formset_factory(BookForm)
+ if request.method == 'POST':
+ article_formset = ArticleFormSet(request.POST, request.FILES, prefix='articles')
+ book_formset = BookFormSet(request.POST, request.FILES, prefix='books')
+ if article_formset.is_valid() and book_formset.is_valid():
+ # do something with the cleaned_data on the formsets.
+ pass
+ else:
+ article_formset = ArticleFormSet(prefix='articles')
+ book_formset = BookFormSet(prefix='books')
+ return render_to_response('manage_articles.html', {
+ 'article_formset': article_formset,
+ 'book_formset': book_formset,
+ })
+
+You would then render the formsets as normal. It is important to point out
+that you need to pass ``prefix`` on both the POST and non-POST cases so that
+it is rendered and processed correctly.
diff --git a/parts/django/docs/topics/forms/index.txt b/parts/django/docs/topics/forms/index.txt
new file mode 100644
index 0000000..30b09c0
--- /dev/null
+++ b/parts/django/docs/topics/forms/index.txt
@@ -0,0 +1,402 @@
+==================
+Working with forms
+==================
+
+.. admonition:: About this document
+
+ This document provides an introduction to Django's form handling features.
+ For a more detailed look at specific areas of the forms API, see
+ :doc:`/ref/forms/api`, :doc:`/ref/forms/fields`, and
+ :doc:`/ref/forms/validation`.
+
+.. highlightlang:: html+django
+
+``django.forms`` is Django's form-handling library.
+
+While it is possible to process form submissions just using Django's
+:class:`~django.http.HttpRequest` class, using the form library takes care of a
+number of common form-related tasks. Using it, you can:
+
+ 1. Display an HTML form with automatically generated form widgets.
+ 2. Check submitted data against a set of validation rules.
+ 3. Redisplay a form in the case of validation errors.
+ 4. Convert submitted form data to the relevant Python data types.
+
+Overview
+========
+
+The library deals with these concepts:
+
+.. glossary::
+
+ Widget
+ A class that corresponds to an HTML form widget, e.g.
+ ``<input type="text">`` or ``<textarea>``. This handles rendering of the
+ widget as HTML.
+
+ Field
+ A class that is responsible for doing validation, e.g.
+ an ``EmailField`` that makes sure its data is a valid e-mail address.
+
+ Form
+ A collection of fields that knows how to validate itself and
+ display itself as HTML.
+
+ Form Media
+ The CSS and JavaScript resources that are required to render a form.
+
+The library is decoupled from the other Django components, such as the database
+layer, views and templates. It relies only on Django settings, a couple of
+``django.utils`` helper functions and Django's internationalization hooks (but
+you're not required to be using internationalization features to use this
+library).
+
+Form objects
+============
+
+A Form object encapsulates a sequence of form fields and a collection of
+validation rules that must be fulfilled in order for the form to be accepted.
+Form classes are created as subclasses of ``django.forms.Form`` and
+make use of a declarative style that you'll be familiar with if you've used
+Django's database models.
+
+For example, consider a form used to implement "contact me" functionality on a
+personal Web site:
+
+.. code-block:: python
+
+ from django import forms
+
+ class ContactForm(forms.Form):
+ subject = forms.CharField(max_length=100)
+ message = forms.CharField()
+ sender = forms.EmailField()
+ cc_myself = forms.BooleanField(required=False)
+
+A form is composed of ``Field`` objects. In this case, our form has four
+fields: ``subject``, ``message``, ``sender`` and ``cc_myself``. ``CharField``,
+``EmailField`` and ``BooleanField`` are just three of the available field types;
+a full list can be found in :doc:`/ref/forms/fields`.
+
+If your form is going to be used to directly add or edit a Django model, you can
+use a :doc:`ModelForm </topics/forms/modelforms>` to avoid duplicating your model
+description.
+
+Using a form in a view
+----------------------
+
+The standard pattern for processing a form in a view looks like this:
+
+.. code-block:: python
+
+ def contact(request):
+ if request.method == 'POST': # If the form has been submitted...
+ form = ContactForm(request.POST) # A form bound to the POST data
+ if form.is_valid(): # All validation rules pass
+ # Process the data in form.cleaned_data
+ # ...
+ return HttpResponseRedirect('/thanks/') # Redirect after POST
+ else:
+ form = ContactForm() # An unbound form
+
+ return render_to_response('contact.html', {
+ 'form': form,
+ })
+
+
+There are three code paths here:
+
+ 1. If the form has not been submitted, an unbound instance of ContactForm is
+ created and passed to the template.
+ 2. If the form has been submitted, a bound instance of the form is created
+ using ``request.POST``. If the submitted data is valid, it is processed
+ and the user is re-directed to a "thanks" page.
+ 3. If the form has been submitted but is invalid, the bound form instance is
+ passed on to the template.
+
+.. versionchanged:: 1.0
+ The ``cleaned_data`` attribute was called ``clean_data`` in earlier releases.
+
+The distinction between **bound** and **unbound** forms is important. An unbound
+form does not have any data associated with it; when rendered to the user, it
+will be empty or will contain default values. A bound form does have submitted
+data, and hence can be used to tell if that data is valid. If an invalid bound
+form is rendered it can include inline error messages telling the user where
+they went wrong.
+
+See :ref:`ref-forms-api-bound-unbound` for further information on the
+differences between bound and unbound forms.
+
+Handling file uploads with a form
+---------------------------------
+
+To see how to handle file uploads with your form see
+:ref:`binding-uploaded-files` for more information.
+
+Processing the data from a form
+-------------------------------
+
+Once ``is_valid()`` returns ``True``, you can process the form submission safe
+in the knowledge that it conforms to the validation rules defined by your form.
+While you could access ``request.POST`` directly at this point, it is better to
+access ``form.cleaned_data``. This data has not only been validated but will
+also be converted in to the relevant Python types for you. In the above example,
+``cc_myself`` will be a boolean value. Likewise, fields such as ``IntegerField``
+and ``FloatField`` convert values to a Python int and float respectively.
+
+Extending the above example, here's how the form data could be processed:
+
+.. code-block:: python
+
+ if form.is_valid():
+ subject = form.cleaned_data['subject']
+ message = form.cleaned_data['message']
+ sender = form.cleaned_data['sender']
+ cc_myself = form.cleaned_data['cc_myself']
+
+ recipients = ['info@example.com']
+ if cc_myself:
+ recipients.append(sender)
+
+ from django.core.mail import send_mail
+ send_mail(subject, message, sender, recipients)
+ return HttpResponseRedirect('/thanks/') # Redirect after POST
+
+For more on sending e-mail from Django, see :doc:`/topics/email`.
+
+Displaying a form using a template
+----------------------------------
+
+Forms are designed to work with the Django template language. In the above
+example, we passed our ``ContactForm`` instance to the template using the
+context variable ``form``. Here's a simple example template::
+
+ <form action="/contact/" method="post">
+ {{ form.as_p }}
+ <input type="submit" value="Submit" />
+ </form>
+
+The form only outputs its own fields; it is up to you to provide the surrounding
+``<form>`` tags and the submit button.
+
+``form.as_p`` will output the form with each form field and accompanying label
+wrapped in a paragraph. Here's the output for our example template::
+
+ <form action="/contact/" method="post">
+ <p><label for="id_subject">Subject:</label>
+ <input id="id_subject" type="text" name="subject" maxlength="100" /></p>
+ <p><label for="id_message">Message:</label>
+ <input type="text" name="message" id="id_message" /></p>
+ <p><label for="id_sender">Sender:</label>
+ <input type="text" name="sender" id="id_sender" /></p>
+ <p><label for="id_cc_myself">Cc myself:</label>
+ <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
+ <input type="submit" value="Submit" />
+ </form>
+
+Note that each form field has an ID attribute set to ``id_<field-name>``, which
+is referenced by the accompanying label tag. This is important for ensuring
+forms are accessible to assistive technology such as screen reader software. You
+can also :ref:`customize the way in which labels and ids are generated
+<ref-forms-api-configuring-label>`.
+
+You can also use ``form.as_table`` to output table rows (you'll need to provide
+your own ``<table>`` tags) and ``form.as_ul`` to output list items.
+
+Customizing the form template
+-----------------------------
+
+If the default generated HTML is not to your taste, you can completely customize
+the way a form is presented using the Django template language. Extending the
+above example::
+
+ <form action="/contact/" method="post">
+ {{ form.non_field_errors }}
+ <div class="fieldWrapper">
+ {{ form.subject.errors }}
+ <label for="id_subject">E-mail subject:</label>
+ {{ form.subject }}
+ </div>
+ <div class="fieldWrapper">
+ {{ form.message.errors }}
+ <label for="id_message">Your message:</label>
+ {{ form.message }}
+ </div>
+ <div class="fieldWrapper">
+ {{ form.sender.errors }}
+ <label for="id_sender">Your email address:</label>
+ {{ form.sender }}
+ </div>
+ <div class="fieldWrapper">
+ {{ form.cc_myself.errors }}
+ <label for="id_cc_myself">CC yourself?</label>
+ {{ form.cc_myself }}
+ </div>
+ <p><input type="submit" value="Send message" /></p>
+ </form>
+
+Each named form-field can be output to the template using
+``{{ form.name_of_field }}``, which will produce the HTML needed to display the
+form widget. Using ``{{ form.name_of_field.errors }}`` displays a list of form
+errors, rendered as an unordered list. This might look like::
+
+ <ul class="errorlist">
+ <li>Sender is required.</li>
+ </ul>
+
+The list has a CSS class of ``errorlist`` to allow you to style its appearance.
+If you wish to further customize the display of errors you can do so by looping
+over them::
+
+ {% if form.subject.errors %}
+ <ol>
+ {% for error in form.subject.errors %}
+ <li><strong>{{ error|escape }}</strong></li>
+ {% endfor %}
+ </ol>
+ {% endif %}
+
+Looping over the form's fields
+------------------------------
+
+If you're using the same HTML for each of your form fields, you can reduce
+duplicate code by looping through each field in turn using a ``{% for %}``
+loop::
+
+ <form action="/contact/" method="post">
+ {% for field in form %}
+ <div class="fieldWrapper">
+ {{ field.errors }}
+ {{ field.label_tag }}: {{ field }}
+ </div>
+ {% endfor %}
+ <p><input type="submit" value="Send message" /></p>
+ </form>
+
+Within this loop, ``{{ field }}`` is an instance of :class:`BoundField`.
+``BoundField`` also has the following attributes, which can be useful in your
+templates:
+
+ ``{{ field.label }}``
+ The label of the field, e.g. ``E-mail address``.
+
+ ``{{ field.label_tag }}``
+ The field's label wrapped in the appropriate HTML ``<label>`` tag,
+ e.g. ``<label for="id_email">E-mail address</label>``
+
+ ``{{ field.html_name }}``
+ The name of the field that will be used in the input element's name
+ field. This takes the form prefix into account, if it has been set.
+
+ ``{{ field.help_text }}``
+ Any help text that has been associated with the field.
+
+ ``{{ field.errors }}``
+ Outputs a ``<ul class="errorlist">`` containing any validation errors
+ corresponding to this field. You can customize the presentation of
+ the errors with a ``{% for error in field.errors %}`` loop. In this
+ case, each object in the loop is a simple string containing the error
+ message.
+
+ ``field.is_hidden``
+ This attribute is ``True`` if the form field is a hidden field and
+ ``False`` otherwise. It's not particularly useful as a template
+ variable, but could be useful in conditional tests such as::
+
+ {% if field.is_hidden %}
+ {# Do something special #}
+ {% endif %}
+
+Looping over hidden and visible fields
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you're manually laying out a form in a template, as opposed to relying on
+Django's default form layout, you might want to treat ``<input type="hidden">``
+fields differently than non-hidden fields. For example, because hidden fields
+don't display anything, putting error messages "next to" the field could cause
+confusion for your users -- so errors for those fields should be handled
+differently.
+
+Django provides two methods on a form that allow you to loop over the hidden
+and visible fields independently: ``hidden_fields()`` and
+``visible_fields()``. Here's a modification of an earlier example that uses
+these two methods::
+
+ <form action="/contact/" method="post">
+ {% for field in form.visible_fields %}
+ <div class="fieldWrapper">
+
+ {# Include the hidden fields in the form #}
+ {% if forloop.first %}
+ {% for hidden in form.hidden_fields %}
+ {{ hidden }}
+ {% endfor %}
+ {% endif %}
+
+ {{ field.errors }}
+ {{ field.label_tag }}: {{ field }}
+ </div>
+ {% endfor %}
+ <p><input type="submit" value="Send message" /></p>
+ </form>
+
+This example does not handle any errors in the hidden fields. Usually, an
+error in a hidden field is a sign of form tampering, since normal form
+interaction won't alter them. However, you could easily insert some error
+displays for those form errors, as well.
+
+.. versionadded:: 1.1
+ The ``hidden_fields`` and ``visible_fields`` methods are new in Django
+ 1.1.
+
+Reusable form templates
+-----------------------
+
+If your site uses the same rendering logic for forms in multiple places, you
+can reduce duplication by saving the form's loop in a standalone template and
+using the :ttag:`include` tag to reuse it in other templates::
+
+ <form action="/contact/" method="post">
+ {% include "form_snippet.html" %}
+ <p><input type="submit" value="Send message" /></p>
+ </form>
+
+ # In form_snippet.html:
+
+ {% for field in form %}
+ <div class="fieldWrapper">
+ {{ field.errors }}
+ {{ field.label_tag }}: {{ field }}
+ </div>
+ {% endfor %}
+
+If the form object passed to a template has a different name within the
+context, you can alias it using the :ttag:`with` tag::
+
+ <form action="/comments/add/" method="post">
+ {% with comment_form as form %}
+ {% include "form_snippet.html" %}
+ {% endwith %}
+ <p><input type="submit" value="Submit comment" /></p>
+ </form>
+
+If you find yourself doing this often, you might consider creating a custom
+:ref:`inclusion tag<howto-custom-template-tags-inclusion-tags>`.
+
+Further topics
+==============
+
+This covers the basics, but forms can do a whole lot more:
+
+.. toctree::
+ :maxdepth: 2
+
+ modelforms
+ formsets
+ media
+
+.. seealso::
+
+ :doc:`The Forms Reference </ref/forms/index>`
+ Covers the full API reference, including form fields, form widgets,
+ and form and field validation.
diff --git a/parts/django/docs/topics/forms/media.txt b/parts/django/docs/topics/forms/media.txt
new file mode 100644
index 0000000..fe70894
--- /dev/null
+++ b/parts/django/docs/topics/forms/media.txt
@@ -0,0 +1,309 @@
+Form Media
+==========
+
+Rendering an attractive and easy-to-use Web form requires more than just
+HTML - it also requires CSS stylesheets, and if you want to use fancy
+"Web2.0" widgets, you may also need to include some JavaScript on each
+page. The exact combination of CSS and JavaScript that is required for
+any given page will depend upon the widgets that are in use on that page.
+
+This is where Django media definitions come in. Django allows you to
+associate different media files with the forms and widgets that require
+that media. For example, if you want to use a calendar to render DateFields,
+you can define a custom Calendar widget. This widget can then be associated
+with the CSS and JavaScript that is required to render the calendar. When
+the Calendar widget is used on a form, Django is able to identify the CSS and
+JavaScript files that are required, and provide the list of file names
+in a form suitable for easy inclusion on your Web page.
+
+.. admonition:: Media and Django Admin
+
+ The Django Admin application defines a number of customized widgets
+ for calendars, filtered selections, and so on. These widgets define
+ media requirements, and the Django Admin uses the custom widgets
+ in place of the Django defaults. The Admin templates will only include
+ those media files that are required to render the widgets on any
+ given page.
+
+ If you like the widgets that the Django Admin application uses,
+ feel free to use them in your own application! They're all stored
+ in ``django.contrib.admin.widgets``.
+
+.. admonition:: Which JavaScript toolkit?
+
+ Many JavaScript toolkits exist, and many of them include widgets (such
+ as calendar widgets) that can be used to enhance your application.
+ Django has deliberately avoided blessing any one JavaScript toolkit.
+ Each toolkit has its own relative strengths and weaknesses - use
+ whichever toolkit suits your requirements. Django is able to integrate
+ with any JavaScript toolkit.
+
+Media as a static definition
+----------------------------
+
+The easiest way to define media is as a static definition. Using this method,
+the media declaration is an inner class. The properties of the inner class
+define the media requirements.
+
+Here's a simple example::
+
+ class CalendarWidget(forms.TextInput):
+ class Media:
+ css = {
+ 'all': ('pretty.css',)
+ }
+ js = ('animations.js', 'actions.js')
+
+This code defines a ``CalendarWidget``, which will be based on ``TextInput``.
+Every time the CalendarWidget is used on a form, that form will be directed
+to include the CSS file ``pretty.css``, and the JavaScript files
+``animations.js`` and ``actions.js``.
+
+This static media definition is converted at runtime into a widget property
+named ``media``. The media for a CalendarWidget instance can be retrieved
+through this property::
+
+ >>> w = CalendarWidget()
+ >>> print w.media
+ <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
+ <script type="text/javascript" src="http://media.example.com/animations.js"></script>
+ <script type="text/javascript" src="http://media.example.com/actions.js"></script>
+
+Here's a list of all possible ``Media`` options. There are no required options.
+
+``css``
+~~~~~~~
+
+A dictionary describing the CSS files required for various forms of output
+media.
+
+The values in the dictionary should be a tuple/list of file names. See
+`the section on media paths`_ for details of how to specify paths to media
+files.
+
+.. _the section on media paths: `Paths in media definitions`_
+
+The keys in the dictionary are the output media types. These are the same
+types accepted by CSS files in media declarations: 'all', 'aural', 'braille',
+'embossed', 'handheld', 'print', 'projection', 'screen', 'tty' and 'tv'. If
+you need to have different stylesheets for different media types, provide
+a list of CSS files for each output medium. The following example would
+provide two CSS options -- one for the screen, and one for print::
+
+ class Media:
+ css = {
+ 'screen': ('pretty.css',),
+ 'print': ('newspaper.css',)
+ }
+
+If a group of CSS files are appropriate for multiple output media types,
+the dictionary key can be a comma separated list of output media types.
+In the following example, TV's and projectors will have the same media
+requirements::
+
+ class Media:
+ css = {
+ 'screen': ('pretty.css',),
+ 'tv,projector': ('lo_res.css',),
+ 'print': ('newspaper.css',)
+ }
+
+If this last CSS definition were to be rendered, it would become the following HTML::
+
+ <link href="http://media.example.com/pretty.css" type="text/css" media="screen" rel="stylesheet" />
+ <link href="http://media.example.com/lo_res.css" type="text/css" media="tv,projector" rel="stylesheet" />
+ <link href="http://media.example.com/newspaper.css" type="text/css" media="print" rel="stylesheet" />
+
+``js``
+~~~~~~
+
+A tuple describing the required JavaScript files. See
+`the section on media paths`_ for details of how to specify paths to media
+files.
+
+``extend``
+~~~~~~~~~~
+
+A boolean defining inheritance behavior for media declarations.
+
+By default, any object using a static media definition will inherit all the
+media associated with the parent widget. This occurs regardless of how the
+parent defines its media requirements. For example, if we were to extend our
+basic Calendar widget from the example above::
+
+ >>> class FancyCalendarWidget(CalendarWidget):
+ ... class Media:
+ ... css = {
+ ... 'all': ('fancy.css',)
+ ... }
+ ... js = ('whizbang.js',)
+
+ >>> w = FancyCalendarWidget()
+ >>> print w.media
+ <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
+ <link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
+ <script type="text/javascript" src="http://media.example.com/animations.js"></script>
+ <script type="text/javascript" src="http://media.example.com/actions.js"></script>
+ <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
+
+The FancyCalendar widget inherits all the media from it's parent widget. If
+you don't want media to be inherited in this way, add an ``extend=False``
+declaration to the media declaration::
+
+ >>> class FancyCalendarWidget(CalendarWidget):
+ ... class Media:
+ ... extend = False
+ ... css = {
+ ... 'all': ('fancy.css',)
+ ... }
+ ... js = ('whizbang.js',)
+
+ >>> w = FancyCalendarWidget()
+ >>> print w.media
+ <link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
+ <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
+
+If you require even more control over media inheritance, define your media
+using a `dynamic property`_. Dynamic properties give you complete control over
+which media files are inherited, and which are not.
+
+.. _dynamic property: `Media as a dynamic property`_
+
+Media as a dynamic property
+---------------------------
+
+If you need to perform some more sophisticated manipulation of media
+requirements, you can define the media property directly. This is done
+by defining a widget property that returns an instance of ``forms.Media``.
+The constructor for ``forms.Media`` accepts ``css`` and ``js`` keyword
+arguments in the same format as that used in a static media definition.
+
+For example, the static media definition for our Calendar Widget could
+also be defined in a dynamic fashion::
+
+ class CalendarWidget(forms.TextInput):
+ def _media(self):
+ return forms.Media(css={'all': ('pretty.css',)},
+ js=('animations.js', 'actions.js'))
+ media = property(_media)
+
+See the section on `Media objects`_ for more details on how to construct
+return values for dynamic media properties.
+
+Paths in media definitions
+--------------------------
+
+Paths used to specify media can be either relative or absolute. If a path
+starts with '/', 'http://' or 'https://', it will be interpreted as an absolute
+path, and left as-is. All other paths will be prepended with the value of
+``settings.MEDIA_URL``. For example, if the MEDIA_URL for your site was
+``http://media.example.com/``::
+
+ class CalendarWidget(forms.TextInput):
+ class Media:
+ css = {
+ 'all': ('/css/pretty.css',),
+ }
+ js = ('animations.js', 'http://othersite.com/actions.js')
+
+ >>> w = CalendarWidget()
+ >>> print w.media
+ <link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" />
+ <script type="text/javascript" src="http://media.example.com/animations.js"></script>
+ <script type="text/javascript" src="http://othersite.com/actions.js"></script>
+
+Media objects
+-------------
+
+When you interrogate the media attribute of a widget or form, the value that
+is returned is a ``forms.Media`` object. As we have already seen, the string
+representation of a Media object is the HTML required to include media
+in the ``<head>`` block of your HTML page.
+
+However, Media objects have some other interesting properties.
+
+Media subsets
+~~~~~~~~~~~~~
+
+If you only want media of a particular type, you can use the subscript operator
+to filter out a medium of interest. For example::
+
+ >>> w = CalendarWidget()
+ >>> print w.media
+ <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
+ <script type="text/javascript" src="http://media.example.com/animations.js"></script>
+ <script type="text/javascript" src="http://media.example.com/actions.js"></script>
+
+ >>> print w.media['css']
+ <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
+
+When you use the subscript operator, the value that is returned is a new
+Media object -- but one that only contains the media of interest.
+
+Combining media objects
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Media objects can also be added together. When two media objects are added,
+the resulting Media object contains the union of the media from both files::
+
+ >>> class CalendarWidget(forms.TextInput):
+ ... class Media:
+ ... css = {
+ ... 'all': ('pretty.css',)
+ ... }
+ ... js = ('animations.js', 'actions.js')
+
+ >>> class OtherWidget(forms.TextInput):
+ ... class Media:
+ ... js = ('whizbang.js',)
+
+ >>> w1 = CalendarWidget()
+ >>> w2 = OtherWidget()
+ >>> print w1.media + w2.media
+ <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
+ <script type="text/javascript" src="http://media.example.com/animations.js"></script>
+ <script type="text/javascript" src="http://media.example.com/actions.js"></script>
+ <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
+
+Media on Forms
+--------------
+
+Widgets aren't the only objects that can have media definitions -- forms
+can also define media. The rules for media definitions on forms are the
+same as the rules for widgets: declarations can be static or dynamic;
+path and inheritance rules for those declarations are exactly the same.
+
+Regardless of whether you define a media declaration, *all* Form objects
+have a media property. The default value for this property is the result
+of adding the media definitions for all widgets that are part of the form::
+
+ >>> class ContactForm(forms.Form):
+ ... date = DateField(widget=CalendarWidget)
+ ... name = CharField(max_length=40, widget=OtherWidget)
+
+ >>> f = ContactForm()
+ >>> f.media
+ <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
+ <script type="text/javascript" src="http://media.example.com/animations.js"></script>
+ <script type="text/javascript" src="http://media.example.com/actions.js"></script>
+ <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
+
+If you want to associate additional media with a form -- for example, CSS for form
+layout -- simply add a media declaration to the form::
+
+ >>> class ContactForm(forms.Form):
+ ... date = DateField(widget=CalendarWidget)
+ ... name = CharField(max_length=40, widget=OtherWidget)
+ ...
+ ... class Media:
+ ... css = {
+ ... 'all': ('layout.css',)
+ ... }
+
+ >>> f = ContactForm()
+ >>> f.media
+ <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
+ <link href="http://media.example.com/layout.css" type="text/css" media="all" rel="stylesheet" />
+ <script type="text/javascript" src="http://media.example.com/animations.js"></script>
+ <script type="text/javascript" src="http://media.example.com/actions.js"></script>
+ <script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
diff --git a/parts/django/docs/topics/forms/modelforms.txt b/parts/django/docs/topics/forms/modelforms.txt
new file mode 100644
index 0000000..23ed9a7
--- /dev/null
+++ b/parts/django/docs/topics/forms/modelforms.txt
@@ -0,0 +1,885 @@
+==========================
+Creating forms from models
+==========================
+
+.. module:: django.forms.models
+ :synopsis: ModelForm and ModelFormset.
+
+.. currentmodule:: django.forms
+
+``ModelForm``
+=============
+.. class:: 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.forms import ModelForm
+
+ # Create the form class.
+ >>> class ArticleForm(ModelForm):
+ ... class Meta:
+ ... model = Article
+
+ # Creating a form to add an article.
+ >>> form = ArticleForm()
+
+ # Creating a form to change an existing article.
+ >>> article = Article.objects.get(pk=1)
+ >>> form = ArticleForm(instance=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
+
+ ``BigIntegerField`` ``IntegerField`` with ``min_value`` set
+ to -9223372036854775808 and ``max_value``
+ set to 9223372036854775807.
+
+ ``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`` ``SlugField``
+
+ ``SmallIntegerField`` ``IntegerField``
+
+ ``TextField`` ``CharField`` with
+ ``widget=forms.Textarea``
+
+ ``TimeField`` ``TimeField``
+
+ ``URLField`` ``URLField`` with ``verify_exists`` set
+ to the model field's ``verify_exists``
+
+ ``XMLField`` ``CharField`` with
+ ``widget=forms.Textarea``
+ =============================== ========================================
+
+
+.. versionadded:: 1.0
+ The ``FloatField`` form field and ``DecimalField`` model and form fields
+ are new in Django 1.0.
+
+.. versionadded:: 1.2
+ The ``BigIntegerField`` is new in Django 1.2.
+
+
+As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field
+types are special cases:
+
+ * ``ForeignKey`` is represented by ``django.forms.ModelChoiceField``,
+ which is a ``ChoiceField`` whose choices are a model ``QuerySet``.
+
+ * ``ManyToManyField`` is represented by
+ ``django.forms.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 or widgets`_ below.
+
+A full example
+--------------
+
+Consider this set of models::
+
+ from django.db import models
+ from django.forms import ModelForm
+
+ 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 ``is_valid()`` method and ``errors``
+----------------------------------------
+
+.. versionchanged:: 1.2
+
+The first time you call ``is_valid()`` or access the ``errors`` attribute of a
+``ModelForm`` has always triggered form validation, but as of Django 1.2, it
+will also trigger :ref:`model validation <validating-objects>`. This has the
+side-effect of cleaning the model you pass to the ``ModelForm`` constructor.
+For instance, calling ``is_valid()`` on your form will convert any date fields
+on your model to actual date objects.
+
+
+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`` can accept an existing
+model instance as the keyword argument ``instance``; if this is
+supplied, ``save()`` will update that instance. If it's not supplied,
+``save()`` will create a new instance of the specified model::
+
+ # 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()
+
+ # Create a form to edit an existing Article.
+ >>> a = Article.objects.get(pk=1)
+ >>> f = ArticleForm(instance=a)
+ >>> f.save()
+
+ # Create a form to edit an existing Article, but use
+ # POST data to populate the form.
+ >>> a = Article.objects.get(pk=1)
+ >>> f = ArticleForm(request.POST, instance=a)
+ >>> f.save()
+
+Note that ``save()`` will raise a ``ValueError`` if the data in the form
+doesn't validate -- i.e., if form.errors evaluates to True.
+
+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, or if you want to use one of the specialized
+:ref:`model saving options <ref-models-force-insert>`. ``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.
+ >>> 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.
+ >>> a = Author()
+ >>> f = AuthorForm(request.POST, instance=a)
+
+ # Create and save the new author instance. There's no need to do anything else.
+ >>> new_author = f.save()
+
+Other than the ``save()`` and ``save_m2m()`` methods, a ``ModelForm`` works
+exactly the same way as any other ``forms`` form. For example, the
+``is_valid()`` method is used to check for validity, the ``is_multipart()``
+method is used to determine whether a form requires multipart file upload (and
+hence whether ``request.FILES`` must be passed to the form), etc. See
+:ref:`binding-uploaded-files` for more information.
+
+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.
+
+ .. versionchanged:: 1.1
+
+ The form will render the fields in the same order they are specified in the
+ ``fields`` attribute.
+
+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 from 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::
+
+ author = Author(title='Mr')
+ form = PartialAuthorForm(request.POST, instance=author)
+ form.save()
+
+ Alternatively, you can use ``save(commit=False)`` and manually set
+ any extra required fields::
+
+ form = PartialAuthorForm(request.POST)
+ author = form.save(commit=False)
+ author.title = 'Mr'
+ author.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 or widgets
+---------------------------------------------
+
+.. versionadded:: 1.2
+ The ``widgets`` attribute is new in Django 1.2.
+
+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 and
+widget for a given model field.
+
+To specify a custom widget for a field, use the ``widgets`` attribute of the
+inner ``Meta`` class. This should be a dictionary mapping field names to widget
+classes or instances.
+
+For example, if you want the a ``CharField`` for the ``name``
+attribute of ``Author`` to be represented by a ``<textarea>`` instead
+of its default ``<input type="text">``, you can override the field's
+widget::
+
+ from django.forms import ModelForm, Textarea
+
+ class AuthorForm(ModelForm):
+ class Meta:
+ model = Author
+ fields = ('name', 'title', 'birth_date')
+ widgets = {
+ 'name': Textarea(attrs={'cols': 80, 'rows': 20}),
+ }
+
+The ``widgets`` dictionary accepts either widget instances (e.g.,
+``Textarea(...)``) or classes (e.g., ``Textarea``).
+
+If you want to further customize a field -- including its type, label, etc. --
+you can 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
+
+If you want to override a field's default label, then specify the ``label``
+parameter when declaring the form field::
+
+ >>> class ArticleForm(ModelForm):
+ ... pub_date = DateField(label='Publication date')
+ ...
+ ... class Meta:
+ ... model = Article
+
+.. note::
+
+ If you explicitly instantiate a form field like this, Django assumes that you
+ want to completely define its behavior; therefore, default attributes (such as
+ ``max_length`` or ``required``) are not drawn from the corresponding model. If
+ you want to maintain the behavior specified in the model, you must set the
+ relevant arguments explicitly when declaring the form field.
+
+ For example, if the ``Article`` model looks like this::
+
+ class Article(models.Model):
+ headline = models.CharField(max_length=200, null=True, blank=True,
+ help_text="Use puns liberally")
+ content = models.TextField()
+
+ and you want to do some custom validation for ``headline``, while keeping
+ the ``blank`` and ``help_text`` values as specified, you might define
+ ``ArticleForm`` like this::
+
+ class ArticleForm(ModelForm):
+ headline = MyFormField(max_length=200, required=False,
+ help_text="Use puns liberally")
+
+ class Meta:
+ model = Article
+
+ See the :doc:`form field documentation </ref/forms/fields>` for more information
+ on fields and their arguments.
+
+Changing the order of fields
+----------------------------
+
+.. versionadded:: 1.1
+
+By default, a ``ModelForm`` will render fields in the same order that they are
+defined on the model, with ``ManyToManyField`` instances appearing last. If
+you want to change the order in which fields are rendered, you can use the
+``fields`` attribute on the ``Meta`` class.
+
+The ``fields`` attribute defines the subset of model fields that will be
+rendered, and the order in which they will be rendered. For example given this
+model::
+
+ class Book(models.Model):
+ author = models.ForeignKey(Author)
+ title = models.CharField(max_length=100)
+
+the ``author`` field would be rendered first. If we wanted the title field
+to be rendered first, we could specify the following ``ModelForm``::
+
+ >>> class BookForm(ModelForm):
+ ... class Meta:
+ ... model = Book
+ ... fields = ('title', 'author')
+
+.. _overriding-modelform-clean-method:
+
+Overriding the clean() method
+-----------------------------
+
+You can override the ``clean()`` method on a model form to provide additional
+validation in the same way you can on a normal form.
+
+In this regard, model forms have two specific characteristics when compared to
+forms:
+
+By default the ``clean()`` method validates the uniqueness of fields that are
+marked as ``unique``, ``unique_together`` or ``unique_for_date|month|year`` on
+the model. Therefore, if you would like to override the ``clean()`` method and
+maintain the default validation, you must call the parent class's ``clean()``
+method.
+
+Also, a model form instance bound to a model object will contain a
+``self.instance`` attribute that gives model form methods access to that
+specific model instance.
+
+Form inheritance
+----------------
+
+As with basic forms, you can extend and reuse ``ModelForms`` by inheriting
+them. This is useful if you need to declare extra fields or extra methods on a
+parent class for use in a number of forms derived from models. For example,
+using the previous ``ArticleForm`` class::
+
+ >>> class EnhancedArticleForm(ArticleForm):
+ ... def clean_pub_date(self):
+ ... ...
+
+This creates a form that behaves identically to ``ArticleForm``, except there's
+some extra validation and cleaning for the ``pub_date`` field.
+
+You can also subclass the parent's ``Meta`` inner class if you want to change
+the ``Meta.fields`` or ``Meta.excludes`` lists::
+
+ >>> class RestrictedArticleForm(EnhancedArticleForm):
+ ... class Meta(ArticleForm.Meta):
+ ... exclude = ('body',)
+
+This adds the extra method from the ``EnhancedArticleForm`` and modifies
+the original ``ArticleForm.Meta`` to remove one field.
+
+There are a couple of things to note, however.
+
+ * Normal Python name resolution rules apply. If you have multiple base
+ classes that declare a ``Meta`` inner class, only the first one will be
+ used. This means the child's ``Meta``, if it exists, otherwise the
+ ``Meta`` of the first parent, etc.
+
+ * For technical reasons, a subclass cannot inherit from both a ``ModelForm``
+ and a ``Form`` simultaneously.
+
+Chances are these notes won't affect you unless you're trying to do something
+tricky with subclassing.
+
+Interaction with model validation
+---------------------------------
+
+As part of its validation process, ``ModelForm`` will call the ``clean()``
+method of each field on your model that has a corresponding field on your form.
+If you have excluded any model fields, validation will not be run on those
+fields. See the :doc:`form validation </ref/forms/validation>` documentation
+for more on how field cleaning and validation work. Also, your model's
+``clean()`` method will be called before any uniqueness checks are made. See
+:ref:`Validating objects <validating-objects>` for more information on the
+model's ``clean()`` hook.
+
+.. _model-formsets:
+
+Model formsets
+==============
+
+Like :doc:`regular formsets </topics/forms/formsets>`, Django provides a couple
+of enhanced formset classes that make it easy to work with Django models. Let's
+reuse the ``Author`` model from above::
+
+ >>> from django.forms.models import modelformset_factory
+ >>> AuthorFormSet = modelformset_factory(Author)
+
+This will create a formset that is capable of working with the data associated
+with the ``Author`` model. It works just like a regular formset::
+
+ >>> formset = AuthorFormSet()
+ >>> print formset
+ <input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS" /><input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS" />
+ <tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" /></td></tr>
+ <tr><th><label for="id_form-0-title">Title:</label></th><td><select name="form-0-title" id="id_form-0-title">
+ <option value="" selected="selected">---------</option>
+ <option value="MR">Mr.</option>
+ <option value="MRS">Mrs.</option>
+ <option value="MS">Ms.</option>
+ </select></td></tr>
+ <tr><th><label for="id_form-0-birth_date">Birth date:</label></th><td><input type="text" name="form-0-birth_date" id="id_form-0-birth_date" /><input type="hidden" name="form-0-id" id="id_form-0-id" /></td></tr>
+
+.. note::
+ ``modelformset_factory`` uses ``formset_factory`` to generate formsets.
+ This means that a model formset is just an extension of a basic formset
+ that knows how to interact with a particular model.
+
+Changing the queryset
+---------------------
+
+By default, when you create a formset from a model, the formset will use a
+queryset that includes all objects in the model (e.g.,
+``Author.objects.all()``). You can override this behavior by using the
+``queryset`` argument::
+
+ >>> formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
+
+Alternatively, you can create a subclass that sets ``self.queryset`` in
+``__init__``::
+
+ from django.forms.models import BaseModelFormSet
+
+ class BaseAuthorFormSet(BaseModelFormSet):
+ def __init__(self, *args, **kwargs):
+ super(BaseAuthorFormSet, self).__init__(*args, **kwargs)
+ self.queryset = Author.objects.filter(name__startswith='O')
+
+Then, pass your ``BaseAuthorFormSet`` class to the factory function::
+
+ >>> AuthorFormSet = modelformset_factory(Author, formset=BaseAuthorFormSet)
+
+If you want to return a formset that doesn't include *any* pre-existing
+instances of the model, you can specify an empty QuerySet::
+
+ >>> AuthorFormSet(queryset=Author.objects.none())
+
+
+Controlling which fields are used with ``fields`` and ``exclude``
+-----------------------------------------------------------------
+
+By default, a model formset uses all fields in the model that are not marked
+with ``editable=False``. However, this can be overridden at the formset level::
+
+ >>> AuthorFormSet = modelformset_factory(Author, fields=('name', 'title'))
+
+Using ``fields`` restricts the formset to use only the given fields.
+Alternatively, you can take an "opt-out" approach, specifying which fields to
+exclude::
+
+ >>> AuthorFormSet = modelformset_factory(Author, exclude=('birth_date',))
+
+.. _saving-objects-in-the-formset:
+
+Saving objects in the formset
+-----------------------------
+
+As with a ``ModelForm``, you can save the data as a model object. This is done
+with the formset's ``save()`` method::
+
+ # Create a formset instance with POST data.
+ >>> formset = AuthorFormSet(request.POST)
+
+ # Assuming all is valid, save the data.
+ >>> instances = formset.save()
+
+The ``save()`` method returns the instances that have been saved to the
+database. If a given instance's data didn't change in the bound data, the
+instance won't be saved to the database and won't be included in the return
+value (``instances``, in the above example).
+
+Pass ``commit=False`` to return the unsaved model instances::
+
+ # don't save to the database
+ >>> instances = formset.save(commit=False)
+ >>> for instance in instances:
+ ... # do something with instance
+ ... instance.save()
+
+This gives you the ability to attach data to the instances before saving them
+to the database. If your formset contains a ``ManyToManyField``, you'll also
+need to call ``formset.save_m2m()`` to ensure the many-to-many relationships
+are saved properly.
+
+.. _model-formsets-max-num:
+
+Limiting the number of editable objects
+---------------------------------------
+
+.. versionchanged:: 1.2
+
+As with regular formsets, you can use the ``max_num`` and ``extra`` parameters
+to ``modelformset_factory`` to limit the number of extra forms displayed.
+
+``max_num`` does not prevent existing objects from being displayed::
+
+ >>> Author.objects.order_by('name')
+ [<Author: Charles Baudelaire>, <Author: Paul Verlaine>, <Author: Walt Whitman>]
+
+ >>> AuthorFormSet = modelformset_factory(Author, max_num=1)
+ >>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
+ >>> [x.name for x in formset.get_queryset()]
+ [u'Charles Baudelaire', u'Paul Verlaine', u'Walt Whitman']
+
+If the value of ``max_num`` is greater than the number of existing related
+objects, up to ``extra`` additional blank forms will be added to the formset,
+so long as the total number of forms does not exceed ``max_num``::
+
+ >>> AuthorFormSet = modelformset_factory(Author, max_num=4, extra=2)
+ >>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
+ >>> for form in formset.forms:
+ ... print form.as_table()
+ <tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" value="Charles Baudelaire" maxlength="100" /><input type="hidden" name="form-0-id" value="1" id="id_form-0-id" /></td></tr>
+ <tr><th><label for="id_form-1-name">Name:</label></th><td><input id="id_form-1-name" type="text" name="form-1-name" value="Paul Verlaine" maxlength="100" /><input type="hidden" name="form-1-id" value="3" id="id_form-1-id" /></td></tr>
+ <tr><th><label for="id_form-2-name">Name:</label></th><td><input id="id_form-2-name" type="text" name="form-2-name" value="Walt Whitman" maxlength="100" /><input type="hidden" name="form-2-id" value="2" id="id_form-2-id" /></td></tr>
+ <tr><th><label for="id_form-3-name">Name:</label></th><td><input id="id_form-3-name" type="text" name="form-3-name" maxlength="100" /><input type="hidden" name="form-3-id" id="id_form-3-id" /></td></tr>
+
+.. versionchanged:: 1.2
+
+A ``max_num`` value of ``None`` (the default) puts no limit on the number of
+forms displayed.
+
+Using a model formset in a view
+-------------------------------
+
+Model formsets are very similar to formsets. Let's say we want to present a
+formset to edit ``Author`` model instances::
+
+ def manage_authors(request):
+ AuthorFormSet = modelformset_factory(Author)
+ if request.method == 'POST':
+ formset = AuthorFormSet(request.POST, request.FILES)
+ if formset.is_valid():
+ formset.save()
+ # do something.
+ else:
+ formset = AuthorFormSet()
+ return render_to_response("manage_authors.html", {
+ "formset": formset,
+ })
+
+As you can see, the view logic of a model formset isn't drastically different
+than that of a "normal" formset. The only difference is that we call
+``formset.save()`` to save the data into the database. (This was described
+above, in :ref:`saving-objects-in-the-formset`.)
+
+Overiding ``clean()`` on a ``model_formset``
+--------------------------------------------
+
+Just like with ``ModelForms``, by default the ``clean()`` method of a
+``model_formset`` will validate that none of the items in the formset violate
+the unique constraints on your model (either ``unique``, ``unique_together`` or
+``unique_for_date|month|year``). If you want to overide the ``clean()`` method
+on a ``model_formset`` and maintain this validation, you must call the parent
+class's ``clean`` method::
+
+ class MyModelFormSet(BaseModelFormSet):
+ def clean(self):
+ super(MyModelFormSet, self).clean()
+ # example custom validation across forms in the formset:
+ for form in self.forms:
+ # your custom formset validation
+
+Using a custom queryset
+-----------------------
+
+As stated earlier, you can override the default queryset used by the model
+formset::
+
+ def manage_authors(request):
+ AuthorFormSet = modelformset_factory(Author)
+ if request.method == "POST":
+ formset = AuthorFormSet(request.POST, request.FILES,
+ queryset=Author.objects.filter(name__startswith='O'))
+ if formset.is_valid():
+ formset.save()
+ # Do something.
+ else:
+ formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
+ return render_to_response("manage_authors.html", {
+ "formset": formset,
+ })
+
+Note that we pass the ``queryset`` argument in both the ``POST`` and ``GET``
+cases in this example.
+
+Using the formset in the template
+---------------------------------
+
+.. highlight:: html+django
+
+There are three ways to render a formset in a Django template.
+
+First, you can let the formset do most of the work::
+
+ <form method="post" action="">
+ {{ formset }}
+ </form>
+
+Second, you can manually render the formset, but let the form deal with
+itself::
+
+ <form method="post" action="">
+ {{ formset.management_form }}
+ {% for form in formset.forms %}
+ {{ form }}
+ {% endfor %}
+ </form>
+
+When you manually render the forms yourself, be sure to render the management
+form as shown above. See the :ref:`management form documentation
+<understanding-the-managementform>`.
+
+Third, you can manually render each field::
+
+ <form method="post" action="">
+ {{ formset.management_form }}
+ {% for form in formset.forms %}
+ {% for field in form %}
+ {{ field.label_tag }}: {{ field }}
+ {% endfor %}
+ {% endfor %}
+ </form>
+
+If you opt to use this third method and you don't iterate over the fields with
+a ``{% for %}`` loop, you'll need to render the primary key field. For example,
+if you were rendering the ``name`` and ``age`` fields of a model::
+
+ <form method="post" action="">
+ {{ formset.management_form }}
+ {% for form in formset.forms %}
+ {{ form.id }}
+ <ul>
+ <li>{{ form.name }}</li>
+ <li>{{ form.age }}</li>
+ </ul>
+ {% endfor %}
+ </form>
+
+Notice how we need to explicitly render ``{{ form.id }}``. This ensures that
+the model formset, in the ``POST`` case, will work correctly. (This example
+assumes a primary key named ``id``. If you've explicitly defined your own
+primary key that isn't called ``id``, make sure it gets rendered.)
+
+.. highlight:: python
+
+Inline formsets
+===============
+
+Inline formsets is a small abstraction layer on top of model formsets. These
+simplify the case of working with related objects via a foreign key. Suppose
+you have these two models::
+
+ class Author(models.Model):
+ name = models.CharField(max_length=100)
+
+ class Book(models.Model):
+ author = models.ForeignKey(Author)
+ title = models.CharField(max_length=100)
+
+If you want to create a formset that allows you to edit books belonging to
+a particular author, you could do this::
+
+ >>> from django.forms.models import inlineformset_factory
+ >>> BookFormSet = inlineformset_factory(Author, Book)
+ >>> author = Author.objects.get(name=u'Mike Royko')
+ >>> formset = BookFormSet(instance=author)
+
+.. note::
+ ``inlineformset_factory`` uses ``modelformset_factory`` and marks
+ ``can_delete=True``.
+
+More than one foreign key to the same model
+-------------------------------------------
+
+If your model contains more than one foreign key to the same model, you'll
+need to resolve the ambiguity manually using ``fk_name``. For example, consider
+the following model::
+
+ class Friendship(models.Model):
+ from_friend = models.ForeignKey(Friend)
+ to_friend = models.ForeignKey(Friend)
+ length_in_months = models.IntegerField()
+
+To resolve this, you can use ``fk_name`` to ``inlineformset_factory``::
+
+ >>> FriendshipFormSet = inlineformset_factory(Friend, Friendship, fk_name="from_friend")
+
+Using an inline formset in a view
+---------------------------------
+
+You may want to provide a view that allows a user to edit the related objects
+of a model. Here's how you can do that::
+
+ def manage_books(request, author_id):
+ author = Author.objects.get(pk=author_id)
+ BookInlineFormSet = inlineformset_factory(Author, Book)
+ if request.method == "POST":
+ formset = BookInlineFormSet(request.POST, request.FILES, instance=author)
+ if formset.is_valid():
+ formset.save()
+ # Do something.
+ else:
+ formset = BookInlineFormSet(instance=author)
+ return render_to_response("manage_books.html", {
+ "formset": formset,
+ })
+
+Notice how we pass ``instance`` in both the ``POST`` and ``GET`` cases.