Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Did some much-needed rewriting/editing in the formsets section of doc…

…s/topics/forms/modelsforms.txt. 'It self' is not two words.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@9616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit c006ef574699160af67d6695b88406336ccb5d8b 1 parent 6553ddc
@adrianholovaty adrianholovaty authored
Showing with 73 additions and 77 deletions.
  1. +73 −77 docs/topics/forms/modelforms.txt
View
150 docs/topics/forms/modelforms.txt
@@ -385,19 +385,18 @@ tricky with subclassing.
.. _model-formsets:
-Model Formsets
+Model formsets
==============
-Similar to :ref:`regular formsets <topics-forms-formsets>` there are a couple
-enhanced formset classes that provide all the right things to work with your
-models. Lets reuse the ``Author`` model from above::
+Like :ref:`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
-to the ``Author`` model. It works just like a regular formset just that we are
-working with ``ModelForm`` instances instead of ``Form`` instances::
+with the ``Author`` model. It works just like a regular formset::
>>> formset = AuthorFormSet()
>>> print formset
@@ -419,13 +418,15 @@ working with ``ModelForm`` instances instead of ``Form`` instances::
Changing the queryset
---------------------
-By default when you create a formset from a model the queryset will be all
-objects in the model. This is best shown as ``Author.objects.all()``. This is
-configurable::
+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 use a subclassing based approach::
+Alternatively, you can create a subclass that implements a ``get_queryset()``
+method::
from django.forms.models import BaseModelFormSet
@@ -433,46 +434,44 @@ Alternatively, you can use a subclassing based approach::
def get_queryset(self):
return super(BaseAuthorFormSet, self).get_queryset().filter(name__startswith='O')
-Then your ``BaseAuthorFormSet`` would be passed into the factory function to
-be used as a base::
+Then, pass your ``BaseAuthorFormSet`` class to the factory function::
>>> AuthorFormSet = modelformset_factory(Author, formset=BaseAuthorFormSet)
Controlling which fields are used with ``fields`` and ``exclude``
-----------------------------------------------------------------
-By default a model formset will use all fields in the model that are not marked
-with ``editable=False``. However, this can be overidden at the formset level::
+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`` will restrict the formset to use just the given fields. Or if
-you need to go the other way::
+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',))
-Using ``exclude`` will prevent the given fields from being used in the formset.
-
.. _saving-objects-in-the-formset:
Saving objects in the formset
-----------------------------
-Similar to a ``ModelForm`` you can save the data into the model. This is done
-with the ``save()`` method on 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.
+ # Create a formset instance with POST data.
>>> formset = AuthorFormSet(request.POST)
-
- # assuming all is valid, save the data
+
+ # Assuming all is valid, save the data.
>>> instances = formset.save()
-The ``save()`` method will return the instances that have been saved to the
-database. If an instance did not change in the bound data it will not be
-saved to the database and not found in ``instances`` in the above example.
+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).
-You can optionally pass in ``commit=False`` to ``save()`` to only return the
-model instances without any database interaction::
+Pass ``commit=False`` to return the unsaved model instances::
# don't save to the database
>>> instances = formset.save(commit=False)
@@ -481,18 +480,18 @@ model instances without any database interaction::
... 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 will also
-need to make a call to ``formset.save_m2m()`` to ensure the many-to-many
-relationships are saved properly.
+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 objects editable
+Limiting the number of editable objects
---------------------------------------
-Similar to regular formsets you can use the ``max_num`` parameter to
+As with regular formsets, you can use the ``max_num`` parameter to
``modelformset_factory`` to limit the number of forms displayed. With
-model formsets this will properly limit the query to only select the maximum
+model formsets, this properly limits the query to select only the maximum
number of objects needed::
>>> Author.objects.order_by('name')
@@ -503,8 +502,8 @@ number of objects needed::
>>> formset.initial
[{'id': 1, 'name': u'Charles Baudelaire'}, {'id': 3, 'name': u'Paul Verlaine'}]
-If the value of ``max_num`` is less than the total objects returned it will
-fill the rest with extra forms::
+If the value of ``max_num`` is less than the total objects returned, the
+formset will fill the rest with extra forms::
>>> AuthorFormSet = modelformset_factory(Author, max_num=4, extra=1)
>>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
@@ -518,8 +517,8 @@ fill the rest with extra forms::
Using a model formset in a view
-------------------------------
-Model formsets are very similar to formsets. Lets say we want to present a
-formset to a user to edit ``Author`` model instances::
+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)
@@ -534,16 +533,16 @@ formset to a user to edit ``Author`` model instances::
"formset": formset,
})
-As you can see the view is not drastically different than how to use a formset
-in a view. The only difference is that we call ``formset.save()`` to save the
-data into the database. This is described above in
-:ref:`saving-objects-in-the-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`.)
Using a custom queryset
~~~~~~~~~~~~~~~~~~~~~~~
-As stated earlier you can override the default queryset the model formset
-uses::
+As stated earlier, you can override the default queryset used by the model
+formset::
def manage_authors(request):
AuthorFormSet = modelformset_factory(Author)
@@ -552,27 +551,29 @@ uses::
queryset=Author.objects.filter(name__startswith='O'))
if formset.is_valid():
formset.save()
- # do something.
+ # Do something.
else:
formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
return render_to_response("manage_authors.html", {
"formset": formset,
})
-What is critical to point out here is that you must pass the queryset in both
-the ``POST`` and ``GET`` cases shown above.
+Note that we pass the ``queryset`` argument in both the ``POST`` and ``GET``
+cases in this example.
Using the formset in the template
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-There are three ways you might want to render the formset in your template.
-You can let the formset do most of the work::
+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>
-You can manually render the formset, but let the form deal with it self::
+Second, you can manually render the formset, but let the form deal with
+itself::
<form method="POST" action="">
{{ formset.management_form }}
@@ -582,9 +583,9 @@ You can manually render the formset, but let the form deal with it self::
</form>
When you manually render the forms yourself, be sure to render the management
-form as shown above. Also see the :ref:`management form documentation <understanding-the-managementform>`.
+form as shown above. See the :ref:`management form documentation <understanding-the-managementform>`.
-Or you can just do it all yourself::
+Third, you can manually render each field::
<form method="POST" action="">
{{ formset.management_form }}
@@ -595,10 +596,9 @@ Or you can just do it all yourself::
{% endfor %}
</form>
-It is critical to note that if you opt to do most of the work yourself and you
-don't go with a field ``{% for %}`` loop of the form, as shown in the last
-example, you need to render to the primary key field. For example if you were
-to render just the ``name`` and ``age`` fields of a model::
+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 }}
@@ -611,33 +611,31 @@ to render just the ``name`` and ``age`` fields of a model::
{% endfor %}
</form>
-Notice how we need to explicitly render ``{{ form.id }}``. This will ensure
-the model formset, in the ``POST`` case, will work correctly. The above
-example is assuming a primary key named ``id`` which is the name of the
-implicit primary key Django creates for you when one isn't given. If you have
-explicitly defined your own primary key field just make sure it gets rendered
-(it is likely to be a visible field anyway).
+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.)
-Inline Formsets
+Inline formsets
===============
-Inline formsets is a small abstraction layer on top of model formsets. It
-simplifies the case of working with related objects via a foreign key. Suppose
+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
-some author you might do::
+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'Orson Scott Card')
+ >>> author = Author.objects.get(name=u'Mike Royko')
>>> formset = BookFormSet(instance=author)
.. note::
@@ -647,16 +645,16 @@ some author you might do::
More than one foreign key to the same model
-------------------------------------------
-If your model contains more than one foreign key to the same model you will
-need to resolve the ambiguity manually using ``fk_name``. Given the following
-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 simply use ``fk_name`` to ``inlineformset_factory``::
+To resolve this, you can use ``fk_name`` to ``inlineformset_factory``::
>>> FrienshipFormSet = inlineformset_factory(Friend, Friendship, fk_name="from_friend")
@@ -664,7 +662,7 @@ Using an inline formset in a view
---------------------------------
You may want to provide a view that allows a user to edit the related objects
-of some model. Here is how you might construct this view::
+of a model. Here's how you can do that::
def manage_books(request, author_id):
author = Author.objects.get(pk=author_id)
@@ -673,13 +671,11 @@ of some model. Here is how you might construct this view::
formset = BookInlineFormSet(request.POST, request.FILES, instance=author)
if formset.is_valid():
formset.save()
- # do something
+ # Do something.
else:
formset = BookInlineFormSet(instance=author)
return render_to_response("manage_books.html", {
"formset": formset,
})
-Notice how we pass the instance in both the ``POST`` and ``GET`` cases. This
-is required similiar to model formsets since the ``instance`` is simply used
-to create the queryset for the model formset that lives underneath.
+Notice how we pass ``instance`` in both the ``POST`` and ``GET`` cases.
Please sign in to comment.
Something went wrong with that request. Please try again.