From ef90ca5f42c81dcee39878c9da96af56eb5e29a4 Mon Sep 17 00:00:00 2001 From: Matt Westcott Date: Fri, 30 Jan 2015 23:14:46 +0000 Subject: [PATCH] [1.8.x] Fixed #24255 -- Specifed 'fields' parameter in modelformset_factory / inlineformset_factory examples. Backport of 8d64aae883f7721c33f88276e7c999844085659f from master --- docs/topics/forms/modelforms.txt | 66 ++++++++++++++++---------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt index bfc066d251..e2804cb9f5 100644 --- a/docs/topics/forms/modelforms.txt +++ b/docs/topics/forms/modelforms.txt @@ -671,7 +671,7 @@ There are a couple of things to note, however. You can only use this technique to opt out from a field defined declaratively by a parent class; it won't prevent the ``ModelForm`` metaclass from generating a default field. To opt-out from default fields, see - :ref:`controlling-fields-with-fields-and-exclude`. + :ref:`modelforms-selecting-fields`. .. _modelforms-factory: @@ -716,7 +716,19 @@ reuse the ``Author`` model from above:: >>> from django.forms.models import modelformset_factory >>> from myapp.models import Author - >>> AuthorFormSet = modelformset_factory(Author) + >>> 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',)) + +.. versionchanged:: 1.8 + + In older versions, omitting both ``fields`` and ``exclude`` resulted in + a formset with all the model's fields. Doing this now raises an + :exc:`~django.core.exceptions.ImproperlyConfigured` exception. 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:: @@ -730,8 +742,7 @@ with the ``Author`` model. It works just like a regular formset:: - - + .. note:: @@ -763,7 +774,8 @@ Alternatively, you can create a subclass that sets ``self.queryset`` in Then, pass your ``BaseAuthorFormSet`` class to the factory function:: - >>> AuthorFormSet = modelformset_factory(Author, formset=BaseAuthorFormSet) + >>> AuthorFormSet = modelformset_factory( + ... Author, fields=('name', 'title'), 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:: @@ -795,22 +807,6 @@ It is not always necessary to define a custom model form. The ``modelformset_factory`` function has several arguments which are passed through to ``modelform_factory``, which are described below. -.. _controlling-fields-with-fields-and-exclude: - -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',)) - Specifying widgets to use in the form with ``widgets`` ------------------------------------------------------ @@ -820,7 +816,8 @@ works the same way as the ``widgets`` dictionary on the inner ``Meta`` class of a ``ModelForm`` works:: >>> AuthorFormSet = modelformset_factory( - ... Author, widgets={'name': Textarea(attrs={'cols': 80, 'rows': 20}) + ... Author, fields=('name', 'title'), + ... widgets={'name': Textarea(attrs={'cols': 80, 'rows': 20})}) Enabling localization for fields with ``localized_fields`` ---------------------------------------------------------- @@ -829,7 +826,8 @@ Using the ``localized_fields`` parameter, you can enable localization for fields in the form. >>> AuthorFormSet = modelformset_factory( - ... Author, localized_fields=('value',)) + ... Author, fields=('name', 'title', 'birth_date'), + ... localized_fields=('birth_date',)) If ``localized_fields`` is set to the special value ``'__all__'``, all fields will be localized. @@ -906,7 +904,7 @@ extra forms displayed. >>> Author.objects.order_by('name') [, , ] - >>> AuthorFormSet = modelformset_factory(Author, max_num=1) + >>> AuthorFormSet = modelformset_factory(Author, fields=('name',), max_num=1) >>> formset = AuthorFormSet(queryset=Author.objects.order_by('name')) >>> [x.name for x in formset.get_queryset()] ['Charles Baudelaire', 'Paul Verlaine', 'Walt Whitman'] @@ -915,7 +913,7 @@ 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) + >>> AuthorFormSet = modelformset_factory(Author, fields=('name',), max_num=4, extra=2) >>> formset = AuthorFormSet(queryset=Author.objects.order_by('name')) >>> for form in formset: ... print(form.as_table()) @@ -938,7 +936,7 @@ formset to edit ``Author`` model instances:: from myapp.models import Author def manage_authors(request): - AuthorFormSet = modelformset_factory(Author) + AuthorFormSet = modelformset_factory(Author, fields=('name', 'title')) if request.method == 'POST': formset = AuthorFormSet(request.POST, request.FILES) if formset.is_valid(): @@ -1006,7 +1004,7 @@ formset:: from myapp.models import Author def manage_authors(request): - AuthorFormSet = modelformset_factory(Author) + AuthorFormSet = modelformset_factory(Author, fields=('name', 'title')) if request.method == "POST": formset = AuthorFormSet(request.POST, request.FILES, queryset=Author.objects.filter(name__startswith='O')) @@ -1106,7 +1104,7 @@ 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) + >>> BookFormSet = inlineformset_factory(Author, Book, fields=('title',)) >>> author = Author.objects.get(name='Mike Royko') >>> formset = BookFormSet(instance=author) @@ -1145,7 +1143,8 @@ Then when you create your inline formset, pass in the optional argument ``formset``:: >>> from django.forms.models import inlineformset_factory - >>> BookFormSet = inlineformset_factory(Author, Book, formset=CustomInlineFormSet) + >>> BookFormSet = inlineformset_factory(Author, Book, fields=('title',), + ... formset=CustomInlineFormSet) >>> author = Author.objects.get(name='Mike Royko') >>> formset = BookFormSet(instance=author) @@ -1157,14 +1156,15 @@ 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) + from_friend = models.ForeignKey(Friend, related_name='from_friends') + to_friend = models.ForeignKey(Friend, related_name='friends') length_in_months = models.IntegerField() To resolve this, you can use ``fk_name`` to :func:`~django.forms.models.inlineformset_factory`:: - >>> FriendshipFormSet = inlineformset_factory(Friend, Friendship, fk_name="from_friend") + >>> FriendshipFormSet = inlineformset_factory(Friend, Friendship, fk_name='from_friend', + ... fields=('to_friend', 'length_in_months')) Using an inline formset in a view --------------------------------- @@ -1174,7 +1174,7 @@ 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) + BookInlineFormSet = inlineformset_factory(Author, Book, fields=('title',)) if request.method == "POST": formset = BookInlineFormSet(request.POST, request.FILES, instance=author) if formset.is_valid():