123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932 |
- ==========================
- 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``
- ``GenericIPAddressField`` ``GenericIPAddressField``
- ``ManyToManyField`` ``ModelMultipleChoiceField`` (see
- below)
- ``NullBooleanField`` ``CharField``
- ``PositiveIntegerField`` ``IntegerField``
- ``PositiveSmallIntegerField`` ``IntegerField``
- ``SlugField`` ``SlugField``
- ``SmallIntegerField`` ``IntegerField``
- ``TextField`` ``CharField`` with
- ``widget=forms.Textarea``
- ``TimeField`` ``TimeField``
- ``URLField`` ``URLField``
- =============================== ========================================
- 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.)::
- from django import forms
- 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())
- .. _modelform-is-valid-and-errors:
- The ``is_valid()`` method and ``errors``
- ----------------------------------------
- The first time you call ``is_valid()`` or access the ``errors`` attribute of a
- ``ModelForm`` triggers :ref:`form validation <form-and-field-validation>` as
- well as :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. If form validation fails, only some of the updates
- may be applied. For this reason, you'll probably want to avoid reusing the
- model instance passed to the form, especially if validation fails.
- 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:
- .. code-block:: python
- # 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 if the form :ref:`hasn't been validated
- <modelform-is-valid-and-errors>`, calling ``save()`` will do so by checking
- ``form.errors``. A ``ValueError`` will be raised 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. The order in which the fields names are specified
- in that list is respected when the form renders them.
- 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 ``birth_date`` fields, you would
- specify ``fields`` or ``exclude`` like this::
- class PartialAuthorForm(ModelForm):
- class Meta:
- model = Author
- fields = ('name', 'birth_date')
- class PartialAuthorForm(ModelForm):
- class Meta:
- model = Author
- exclude = ('title',)
- 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. Also, if you
- manually add the excluded fields back to the form, they will not
- be initialized from the model instance.
- 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
- ---------------------------------------------
- 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
- You must ensure that the type of the form field can be used to set the
- contents of the corresponding model field. When they are not compatible,
- you will get a ``ValueError`` as no implicit conversion takes place.
- See the :doc:`form field documentation </ref/forms/fields>` for more information
- on fields and their arguments.
- Changing the order of fields
- ----------------------------
- 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.
- .. _modelforms-factory:
- ModelForm factory function
- --------------------------
- You can create forms from a given model using the standalone function
- :func:`~django.forms.models.modelform_factory`, instead of using a class
- definition. This may be more convenient if you do not have many customizations
- to make::
- >>> from django.forms.models import modelform_factory
- >>> BookForm = modelform_factory(Book)
- This can also be used to make simple modifications to existing forms, for
- example by specifying which fields should be displayed::
- >>> Form = modelform_factory(Book, form=BookForm, fields=("author",))
- ... or which fields should be excluded::
- >>> Form = modelform_factory(Book, form=BookForm, exclude=("title",))
- You can also specify the widgets to be used for a given field::
- >>> from django.forms import Textarea
- >>> Form = modelform_factory(Book, form=BookForm, widgets={"title": Textarea()})
- .. _model-formsets:
- Model formsets
- ==============
- .. class:: models.BaseModelFormSet
- 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::
- :func:`~django.forms.models.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',))
- Providing initial values
- ------------------------
- As with regular formsets, it's possible to :ref:`specify initial data
- <formsets-initial-data>` for forms in the formset by specifying an ``initial``
- parameter when instantiating the model formset class returned by
- :func:`~django.forms.models.modelformset_factory`. However, with model
- formsets, the initial values only apply to extra forms, those that aren't bound
- to an existing object instance.
- .. _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).
- When fields are missing from the form (for example because they have
- been excluded), these fields will not be set by the ``save()``
- method. You can find more information about this restriction, which
- also holds for regular ``ModelForms``, in `Using a subset of fields on
- the form`_.
- 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
- ---------------------------------------
- As with regular formsets, you can use the ``max_num`` and ``extra`` parameters
- to :func:`~django.forms.models.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:
- ... 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>
- 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 override 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 %}
- {{ 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 %}
- {% 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 %}
- {{ 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
- ===============
- 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::
- :func:`~django.forms.models.inlineformset_factory` uses
- :func:`~django.forms.models.modelformset_factory` and marks
- ``can_delete=True``.
- .. seealso::
- :ref:`Manually rendered can_delete and can_order <manually-rendered-can-delete-and-can-order>`.
- 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
- :func:`~django.forms.models.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. Should generally end with a redirect. For example:
- return HttpResponseRedirect(author.get_absolute_url())
- 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.
|