Improved the model formset and inline formset documentation to be more explicit and handle some cases that were never addressed before.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@9614 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Brian Rosner 2008-12-09 00:31:17 +00:00
parent 15bd649940
commit 6553ddc5b4
1 changed files with 111 additions and 8 deletions

View File

@ -530,7 +530,7 @@ formset to a user to edit ``Author`` model instances::
# do something. # do something.
else: else:
formset = AuthorFormSet() formset = AuthorFormSet()
render_to_response("manage_authors.html", { return render_to_response("manage_authors.html", {
"formset": formset, "formset": formset,
}) })
@ -539,12 +539,91 @@ in a view. The only difference is that we call ``formset.save()`` to save the
data into the database. This is described above in data into the database. This is described above in
:ref:`saving-objects-in-the-formset`. :ref:`saving-objects-in-the-formset`.
Using ``inlineformset_factory`` Using a custom queryset
------------------------------- ~~~~~~~~~~~~~~~~~~~~~~~
The ``inlineformset_factory`` is a helper to a common usage pattern of working As stated earlier you can override the default queryset the model formset
with related objects through a foreign key. It takes all the same options as uses::
a ``modelformset_factory``. Suppose you have these two models::
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,
})
What is critical to point out here is that you must pass the queryset in both
the ``POST`` and ``GET`` cases shown above.
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::
<form method="POST" action="">
{{ formset }}
</form>
You can manually render the formset, but let the form deal with it self::
<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. Also see the :ref:`management form documentation <understanding-the-managementform>`.
Or you can just do it all yourself::
<form method="POST" action="">
{{ formset.management_form }}
{% for form in formset.formset %}
{% for fields in form %}
{{ field }}
{% endfor %}
{% 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::
<form method="POST" action="">
{{ formset.management_form }}
{% for form in formset.formset %}
{{ form.id }}
<ul>
<li>{{ form.name }}</li>
<li>{{ form.age }}</li>
</ul>
{% 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).
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
you have these two models::
class Author(models.Model): class Author(models.Model):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
@ -554,7 +633,7 @@ a ``modelformset_factory``. Suppose you have these two models::
title = models.CharField(max_length=100) title = models.CharField(max_length=100)
If you want to create a formset that allows you to edit books belonging to If you want to create a formset that allows you to edit books belonging to
some author you would do:: some author you might do::
>>> from django.forms.models import inlineformset_factory >>> from django.forms.models import inlineformset_factory
>>> BookFormSet = inlineformset_factory(Author, Book) >>> BookFormSet = inlineformset_factory(Author, Book)
@ -566,7 +645,7 @@ some author you would do::
``can_delete=True``. ``can_delete=True``.
More than one foreign key to the same model More than one foreign key to the same model
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -------------------------------------------
If your model contains more than one foreign key to the same model you will 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 need to resolve the ambiguity manually using ``fk_name``. Given the following
@ -580,3 +659,27 @@ model::
To resolve this you can simply use ``fk_name`` to ``inlineformset_factory``:: To resolve this you can simply use ``fk_name`` to ``inlineformset_factory``::
>>> FrienshipFormSet = inlineformset_factory(Friend, Friendship, fk_name="from_friend") >>> FrienshipFormSet = 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 some model. Here is how you might construct this view::
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 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.