mirror of
				https://github.com/django/django.git
				synced 2025-10-28 08:06:09 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1374 lines
		
	
	
		
			50 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1374 lines
		
	
	
		
			50 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| ==========================
 | ||
| Creating forms from models
 | ||
| ==========================
 | ||
| 
 | ||
| .. 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 lets you create a ``Form``
 | ||
| class from a Django model.
 | ||
| 
 | ||
| For example:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> from django.forms import ModelForm
 | ||
|     >>> from myapp.models import Article
 | ||
| 
 | ||
|     # Create the form class.
 | ||
|     >>> class ArticleForm(ModelForm):
 | ||
|     ...     class Meta:
 | ||
|     ...         model = Article
 | ||
|     ...         fields = ["pub_date", "headline", "content", "reporter"]
 | ||
|     ...
 | ||
| 
 | ||
|     # 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
 | ||
| specified, in the order specified in the ``fields`` attribute.
 | ||
| 
 | ||
| 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:
 | ||
| 
 | ||
| .. currentmodule:: django.db.models
 | ||
| 
 | ||
| =================================== ==================================================
 | ||
| Model field                         Form field
 | ||
| =================================== ==================================================
 | ||
| :class:`AutoField`                  Not represented in the form
 | ||
| 
 | ||
| :class:`BigAutoField`               Not represented in the form
 | ||
| 
 | ||
| :class:`BigIntegerField`            :class:`~django.forms.IntegerField` with
 | ||
|                                     ``min_value`` set to -9223372036854775808
 | ||
|                                     and ``max_value`` set to 9223372036854775807.
 | ||
| 
 | ||
| :class:`BinaryField`                :class:`~django.forms.CharField`, if
 | ||
|                                     :attr:`~.Field.editable` is set to
 | ||
|                                     ``True`` on the model field, otherwise not
 | ||
|                                     represented in the form.
 | ||
| 
 | ||
| :class:`BooleanField`               :class:`~django.forms.BooleanField`, or
 | ||
|                                     :class:`~django.forms.NullBooleanField` if
 | ||
|                                     ``null=True``.
 | ||
| 
 | ||
| :class:`CharField`                  :class:`~django.forms.CharField` with
 | ||
|                                     ``max_length`` set to the model field's
 | ||
|                                     ``max_length`` and
 | ||
|                                     :attr:`~django.forms.CharField.empty_value`
 | ||
|                                     set to ``None`` if ``null=True``.
 | ||
| 
 | ||
| :class:`DateField`                  :class:`~django.forms.DateField`
 | ||
| 
 | ||
| :class:`DateTimeField`              :class:`~django.forms.DateTimeField`
 | ||
| 
 | ||
| :class:`DecimalField`               :class:`~django.forms.DecimalField`
 | ||
| 
 | ||
| :class:`DurationField`              :class:`~django.forms.DurationField`
 | ||
| 
 | ||
| :class:`EmailField`                 :class:`~django.forms.EmailField`
 | ||
| 
 | ||
| :class:`FileField`                  :class:`~django.forms.FileField`
 | ||
| 
 | ||
| :class:`FilePathField`              :class:`~django.forms.FilePathField`
 | ||
| 
 | ||
| :class:`FloatField`                 :class:`~django.forms.FloatField`
 | ||
| 
 | ||
| :class:`ForeignKey`                 :class:`~django.forms.ModelChoiceField`
 | ||
|                                     (see below)
 | ||
| 
 | ||
| :class:`ImageField`                 :class:`~django.forms.ImageField`
 | ||
| 
 | ||
| :class:`IntegerField`               :class:`~django.forms.IntegerField`
 | ||
| 
 | ||
| ``IPAddressField``                  ``IPAddressField``
 | ||
| 
 | ||
| :class:`GenericIPAddressField`      :class:`~django.forms.GenericIPAddressField`
 | ||
| 
 | ||
| :class:`JSONField`                  :class:`~django.forms.JSONField`
 | ||
| 
 | ||
| :class:`ManyToManyField`            :class:`~django.forms.ModelMultipleChoiceField`
 | ||
|                                     (see below)
 | ||
| 
 | ||
| :class:`PositiveBigIntegerField`    :class:`~django.forms.IntegerField`
 | ||
| 
 | ||
| :class:`PositiveIntegerField`       :class:`~django.forms.IntegerField`
 | ||
| 
 | ||
| :class:`PositiveSmallIntegerField`  :class:`~django.forms.IntegerField`
 | ||
| 
 | ||
| :class:`SlugField`                  :class:`~django.forms.SlugField`
 | ||
| 
 | ||
| :class:`SmallAutoField`             Not represented in the form
 | ||
| 
 | ||
| :class:`SmallIntegerField`          :class:`~django.forms.IntegerField`
 | ||
| 
 | ||
| :class:`TextField`                  :class:`~django.forms.CharField` with
 | ||
|                                     ``widget=forms.Textarea``
 | ||
| 
 | ||
| :class:`TimeField`                  :class:`~django.forms.TimeField`
 | ||
| 
 | ||
| :class:`URLField`                   :class:`~django.forms.URLField`
 | ||
| 
 | ||
| :class:`UUIDField`                  :class:`~django.forms.UUIDField`
 | ||
| =================================== ==================================================
 | ||
| 
 | ||
| .. currentmodule:: django.forms
 | ||
| 
 | ||
| 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 fields`_ 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 __str__(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
 | ||
|             fields = ["name", "title", "birth_date"]
 | ||
| 
 | ||
| 
 | ||
|     class BookForm(ModelForm):
 | ||
|         class Meta:
 | ||
|             model = Book
 | ||
|             fields = ["name", "authors"]
 | ||
| 
 | ||
| 
 | ||
| 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())
 | ||
| 
 | ||
| .. _validation-on-modelform:
 | ||
| 
 | ||
| Validation on a ``ModelForm``
 | ||
| -----------------------------
 | ||
| 
 | ||
| There are two main steps involved in validating a ``ModelForm``:
 | ||
| 
 | ||
| 1. :doc:`Validating the form </ref/forms/validation>`
 | ||
| 2. :ref:`Validating the model instance <validating-objects>`
 | ||
| 
 | ||
| Just like normal form validation, model form validation is triggered implicitly
 | ||
| when calling :meth:`~django.forms.Form.is_valid()` or accessing the
 | ||
| :attr:`~django.forms.Form.errors` attribute and explicitly when calling
 | ||
| ``full_clean()``, although you will typically not use the latter method in
 | ||
| practice.
 | ||
| 
 | ||
| ``Model`` validation (:meth:`Model.full_clean()
 | ||
| <django.db.models.Model.full_clean()>`) is triggered from within the form
 | ||
| validation step, right after the form's ``clean()`` method is called.
 | ||
| 
 | ||
| .. warning::
 | ||
| 
 | ||
|     The cleaning process modifies the model instance passed to the
 | ||
|     ``ModelForm`` constructor in various ways. For instance, any date fields on
 | ||
|     the model are converted into actual date objects. Failed validation may
 | ||
|     leave the underlying model instance in an inconsistent state and therefore
 | ||
|     it's not recommended to reuse it.
 | ||
| 
 | ||
| .. _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.
 | ||
| 
 | ||
| A model form instance attached to a model object will contain an ``instance``
 | ||
| attribute that gives its methods access to that specific model instance.
 | ||
| 
 | ||
| .. warning::
 | ||
| 
 | ||
|     The ``ModelForm.clean()`` method sets a flag that makes the :ref:`model
 | ||
|     validation <validating-objects>` step validate the uniqueness of model
 | ||
|     fields that are marked as ``unique``, ``unique_together`` or
 | ||
|     ``unique_for_date|month|year``.
 | ||
| 
 | ||
|     If you would like to override the ``clean()`` method and maintain this
 | ||
|     validation, you must call the parent class's ``clean()`` method.
 | ||
| 
 | ||
| Interaction with model validation
 | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | ||
| 
 | ||
| As part of the 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.
 | ||
| 
 | ||
| The 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.
 | ||
| 
 | ||
| .. _considerations-regarding-model-errormessages:
 | ||
| 
 | ||
| Considerations regarding model's ``error_messages``
 | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | ||
| 
 | ||
| Error messages defined at the
 | ||
| :attr:`form field <django.forms.Field.error_messages>` level or at the
 | ||
| :ref:`form Meta <modelforms-overriding-default-fields>` level always take
 | ||
| precedence over the error messages defined at the
 | ||
| :attr:`model field <django.db.models.Field.error_messages>` level.
 | ||
| 
 | ||
| Error messages  defined on :attr:`model fields
 | ||
| <django.db.models.Field.error_messages>` are only used when the
 | ||
| ``ValidationError`` is raised during the :ref:`model validation
 | ||
| <validating-objects>` step and no corresponding error messages are defined at
 | ||
| the form level.
 | ||
| 
 | ||
| You can override the error messages from ``NON_FIELD_ERRORS`` raised by model
 | ||
| validation by adding the :data:`~django.core.exceptions.NON_FIELD_ERRORS` key
 | ||
| to the ``error_messages`` dictionary of the ``ModelForm``’s inner ``Meta`` class::
 | ||
| 
 | ||
|     from django.core.exceptions import NON_FIELD_ERRORS
 | ||
|     from django.forms import ModelForm
 | ||
| 
 | ||
| 
 | ||
|     class ArticleForm(ModelForm):
 | ||
|         class Meta:
 | ||
|             error_messages = {
 | ||
|                 NON_FIELD_ERRORS: {
 | ||
|                     "unique_together": "%(model_name)s's %(field_labels)s are not unique.",
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
| .. _topics-modelform-save:
 | ||
| 
 | ||
| The ``save()`` method
 | ||
| ---------------------
 | ||
| 
 | ||
| Every ``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:: pycon
 | ||
| 
 | ||
|     >>> from myapp.models import Article
 | ||
|     >>> from myapp.forms import ArticleForm
 | ||
| 
 | ||
|     # 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, 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
 | ||
| <validation-on-modelform>`, 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``.
 | ||
| 
 | ||
| If an optional field doesn't appear in the form's data, the resulting model
 | ||
| instance uses the model field :attr:`~django.db.models.Field.default`, if
 | ||
| there is one, for that field. This behavior doesn't apply to fields that use
 | ||
| :class:`~django.forms.CheckboxInput`,
 | ||
| :class:`~django.forms.CheckboxSelectMultiple`, or
 | ||
| :class:`~django.forms.SelectMultiple` (or any custom widget whose
 | ||
| :meth:`~django.forms.Widget.value_omitted_from_data` method always returns
 | ||
| ``False``) since an unchecked checkbox and unselected ``<select multiple>``
 | ||
| don't appear in the data of an HTML form submission. Use a custom form field or
 | ||
| widget if you're designing an API and want the default fallback behavior for a
 | ||
| field that uses one of these widgets.
 | ||
| 
 | ||
| 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:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     # 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 ``save()`` on a form, all data -- including many-to-many data --
 | ||
| is saved without the need for any additional method calls.  For example:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     # 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.
 | ||
| 
 | ||
| .. _modelforms-selecting-fields:
 | ||
| 
 | ||
| Selecting the fields to use
 | ||
| ---------------------------
 | ||
| 
 | ||
| It is strongly recommended that you explicitly set all fields that should be
 | ||
| edited in the form using the ``fields`` attribute. Failure to do so can easily
 | ||
| lead to security problems when a form unexpectedly allows a user to set certain
 | ||
| fields, especially when new fields are added to a model. Depending on how the
 | ||
| form is rendered, the problem may not even be visible on the web page.
 | ||
| 
 | ||
| The alternative approach would be to include all fields automatically, or
 | ||
| remove only some. This fundamental approach is known to be much less secure
 | ||
| and has led to serious exploits on major websites (e.g. `GitHub
 | ||
| <https://github.blog/2012-03-04-public-key-security-vulnerability-and-mitigation/>`_).
 | ||
| 
 | ||
| There are, however, two shortcuts available for cases where you can guarantee
 | ||
| these security concerns do not apply to you:
 | ||
| 
 | ||
| 1. Set the ``fields`` attribute to the special value ``'__all__'`` to indicate
 | ||
|    that all fields in the model should be used. For example::
 | ||
| 
 | ||
|        from django.forms import ModelForm
 | ||
| 
 | ||
| 
 | ||
|        class AuthorForm(ModelForm):
 | ||
|            class Meta:
 | ||
|                model = Author
 | ||
|                fields = "__all__"
 | ||
| 
 | ||
| 2. Set the ``exclude`` attribute of the ``ModelForm``’s inner ``Meta`` class to
 | ||
|    a list of fields to be excluded from the form.
 | ||
| 
 | ||
|    For example::
 | ||
| 
 | ||
|        class PartialAuthorForm(ModelForm):
 | ||
|            class Meta:
 | ||
|                model = Author
 | ||
|                exclude = ["title"]
 | ||
| 
 | ||
|    Since the ``Author`` model has the 3 fields ``name``, ``title`` and
 | ||
|    ``birth_date``, this will result in the fields ``name`` and ``birth_date``
 | ||
|    being present on the form.
 | ||
| 
 | ||
| If either of these are used, the order the fields appear in the form will be the
 | ||
| order the fields are defined in the model, with ``ManyToManyField`` instances
 | ||
| appearing last.
 | ||
| 
 | ||
| In addition, Django applies the following rule: if you set ``editable=False`` on
 | ||
| the model field, *any* form created from the model via ``ModelForm`` will not
 | ||
| include that field.
 | ||
| 
 | ||
| .. note::
 | ||
| 
 | ||
|     Any fields not included in a form by the above logic
 | ||
|     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`_
 | ||
| 
 | ||
| .. _modelforms-overriding-default-fields:
 | ||
| 
 | ||
| Overriding the default fields
 | ||
| -----------------------------
 | ||
| 
 | ||
| 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 for a given model.
 | ||
| 
 | ||
| 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 ``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
 | ||
|     from myapp.models import Author
 | ||
| 
 | ||
| 
 | ||
|     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``). Note that the ``widgets``
 | ||
| dictionary is ignored for a model field with a non-empty ``choices`` attribute.
 | ||
| In this case, you must override the form field to use a different widget.
 | ||
| 
 | ||
| Similarly, you can specify the ``labels``, ``help_texts`` and ``error_messages``
 | ||
| attributes of the inner ``Meta`` class if you want to further customize a field.
 | ||
| 
 | ||
| For example if you wanted to customize the wording of all user facing strings for
 | ||
| the ``name`` field::
 | ||
| 
 | ||
|     from django.utils.translation import gettext_lazy as _
 | ||
| 
 | ||
| 
 | ||
|     class AuthorForm(ModelForm):
 | ||
|         class Meta:
 | ||
|             model = Author
 | ||
|             fields = ["name", "title", "birth_date"]
 | ||
|             labels = {
 | ||
|                 "name": _("Writer"),
 | ||
|             }
 | ||
|             help_texts = {
 | ||
|                 "name": _("Some useful help text."),
 | ||
|             }
 | ||
|             error_messages = {
 | ||
|                 "name": {
 | ||
|                     "max_length": _("This writer's name is too long."),
 | ||
|                 },
 | ||
|             }
 | ||
| 
 | ||
| You can also specify ``field_classes`` or ``formfield_callback`` to customize
 | ||
| the type of fields instantiated by the form.
 | ||
| 
 | ||
| For example, if you wanted to use ``MySlugFormField`` for the ``slug``
 | ||
| field, you could do the following::
 | ||
| 
 | ||
|     from django.forms import ModelForm
 | ||
|     from myapp.models import Article
 | ||
| 
 | ||
| 
 | ||
|     class ArticleForm(ModelForm):
 | ||
|         class Meta:
 | ||
|             model = Article
 | ||
|             fields = ["pub_date", "headline", "content", "reporter", "slug"]
 | ||
|             field_classes = {
 | ||
|                 "slug": MySlugFormField,
 | ||
|             }
 | ||
| 
 | ||
| or::
 | ||
| 
 | ||
|     from django.forms import ModelForm
 | ||
|     from myapp.models import Article
 | ||
| 
 | ||
| 
 | ||
|     def formfield_for_dbfield(db_field, **kwargs):
 | ||
|         if db_field.name == "slug":
 | ||
|             return MySlugFormField()
 | ||
|         return db_field.formfield(**kwargs)
 | ||
| 
 | ||
| 
 | ||
|     class ArticleForm(ModelForm):
 | ||
|         class Meta:
 | ||
|             model = Article
 | ||
|             fields = ["pub_date", "headline", "content", "reporter", "slug"]
 | ||
|             formfield_callback = formfield_for_dbfield
 | ||
| 
 | ||
| Finally, if you want complete control over of a field -- including its type,
 | ||
| validators, required, etc. -- you can do this by declaratively specifying
 | ||
| fields like you would in a regular ``Form``.
 | ||
| 
 | ||
| If you want to specify a field's validators, you can do so by defining
 | ||
| the field declaratively and setting its ``validators`` parameter::
 | ||
| 
 | ||
|     from django.forms import CharField, ModelForm
 | ||
|     from myapp.models import Article
 | ||
| 
 | ||
| 
 | ||
|     class ArticleForm(ModelForm):
 | ||
|         slug = CharField(validators=[validate_slug])
 | ||
| 
 | ||
|         class Meta:
 | ||
|             model = Article
 | ||
|             fields = ["pub_date", "headline", "content", "reporter", "slug"]
 | ||
| 
 | ||
| .. note::
 | ||
| 
 | ||
|     When you explicitly instantiate a form field like this, it is important to
 | ||
|     understand how ``ModelForm`` and regular ``Form`` are related.
 | ||
| 
 | ||
|     ``ModelForm`` is a regular ``Form`` which can automatically generate
 | ||
|     certain fields. The fields that are automatically generated depend on
 | ||
|     the content of the ``Meta`` class and on which fields have already been
 | ||
|     defined declaratively. Basically, ``ModelForm`` will **only** generate fields
 | ||
|     that are **missing** from the form, or in other words, fields that weren't
 | ||
|     defined declaratively.
 | ||
| 
 | ||
|     Fields defined declaratively are left as-is, therefore any customizations
 | ||
|     made to ``Meta`` attributes such as ``widgets``, ``labels``, ``help_texts``,
 | ||
|     or ``error_messages`` are ignored; these only apply to fields that are
 | ||
|     generated automatically.
 | ||
| 
 | ||
|     Similarly, fields defined declaratively do not draw their attributes like
 | ||
|     ``max_length`` or ``required`` 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
 | ||
|                 fields = ["headline", "content"]
 | ||
| 
 | ||
|     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.
 | ||
| 
 | ||
| Enabling localization of fields
 | ||
| -------------------------------
 | ||
| 
 | ||
| By default, the fields in a ``ModelForm`` will not localize their data. To
 | ||
| enable localization for fields, you can use the ``localized_fields``
 | ||
| attribute on the ``Meta`` class.
 | ||
| 
 | ||
|     >>> from django.forms import ModelForm
 | ||
|     >>> from myapp.models import Author
 | ||
|     >>> class AuthorForm(ModelForm):
 | ||
|     ...     class Meta:
 | ||
|     ...         model = Author
 | ||
|     ...         localized_fields = ['birth_date']
 | ||
| 
 | ||
| If ``localized_fields`` is set to the special value ``'__all__'``, all fields
 | ||
| will be localized.
 | ||
| 
 | ||
| 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:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> 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.exclude`` lists:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> 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.
 | ||
| 
 | ||
| * It's possible to inherit from both ``Form`` and ``ModelForm`` simultaneously,
 | ||
|   however, you must ensure that ``ModelForm`` appears first in the MRO. This is
 | ||
|   because these classes rely on different metaclasses and a class can only have
 | ||
|   one metaclass.
 | ||
| 
 | ||
| * It's possible to declaratively remove a ``Field`` inherited from a parent class by
 | ||
|   setting the name to be ``None`` on the subclass.
 | ||
| 
 | ||
|   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:`modelforms-selecting-fields`.
 | ||
| 
 | ||
| Providing initial values
 | ||
| ------------------------
 | ||
| 
 | ||
| As with regular forms, it's possible to specify initial data for forms by
 | ||
| specifying an ``initial`` parameter when instantiating the form. Initial
 | ||
| values provided this way will override both initial values from the form field
 | ||
| and values from an attached model instance. For example:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> article = Article.objects.get(pk=1)
 | ||
|     >>> article.headline
 | ||
|     'My headline'
 | ||
|     >>> form = ArticleForm(initial={"headline": "Initial headline"}, instance=article)
 | ||
|     >>> form["headline"].value()
 | ||
|     'Initial headline'
 | ||
| 
 | ||
| .. _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:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> from django.forms import modelform_factory
 | ||
|     >>> from myapp.models import Book
 | ||
|     >>> BookForm = modelform_factory(Book, fields=["author", "title"])
 | ||
| 
 | ||
| This can also be used to make modifications to existing forms, for example by
 | ||
| specifying the widgets to be used for a given field:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> from django.forms import Textarea
 | ||
|     >>> Form = modelform_factory(Book, form=BookForm, widgets={"title": Textarea()})
 | ||
| 
 | ||
| The fields to include can be specified using the ``fields`` and ``exclude``
 | ||
| keyword arguments, or the corresponding attributes on the ``ModelForm`` inner
 | ||
| ``Meta`` class. Please see the ``ModelForm`` :ref:`modelforms-selecting-fields`
 | ||
| documentation.
 | ||
| 
 | ||
| ... or enable localization for specific fields:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> Form = modelform_factory(Author, form=AuthorForm, localized_fields=["birth_date"])
 | ||
| 
 | ||
| .. _model-formsets:
 | ||
| 
 | ||
| Model formsets
 | ||
| ==============
 | ||
| 
 | ||
| .. class:: models.BaseModelFormSet
 | ||
| 
 | ||
| Like :doc:`regular formsets </topics/forms/formsets>`, Django provides a couple
 | ||
| of enhanced formset classes to make working with Django models more
 | ||
| convenient. Let's reuse the ``Author`` model from above:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> from django.forms import modelformset_factory
 | ||
|     >>> from myapp.models import 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:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> AuthorFormSet = modelformset_factory(Author, exclude=["birth_date"])
 | ||
| 
 | ||
| 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:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> 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-MIN_NUM_FORMS" value="0" id="id_form-MIN_NUM_FORMS"><input type="hidden" name="form-MAX_NUM_FORMS" value="1000" id="id_form-MAX_NUM_FORMS">
 | ||
|     <div><label for="id_form-0-name">Name:</label><input id="id_form-0-name" type="text" name="form-0-name" maxlength="100"></div>
 | ||
|     <div><label for="id_form-0-title">Title:</label><select name="form-0-title" id="id_form-0-title">
 | ||
|     <option value="" selected>---------</option>
 | ||
|     <option value="MR">Mr.</option>
 | ||
|     <option value="MRS">Mrs.</option>
 | ||
|     <option value="MS">Ms.</option>
 | ||
|     </select><input type="hidden" name="form-0-id" id="id_form-0-id"></div>
 | ||
| 
 | ||
| .. note::
 | ||
| 
 | ||
|     :func:`~django.forms.models.modelformset_factory` uses
 | ||
|     :func:`~django.forms.formsets.formset_factory` to generate formsets. This
 | ||
|     means that a model formset is an extension of a basic formset that knows
 | ||
|     how to interact with a particular model.
 | ||
| 
 | ||
| .. note::
 | ||
| 
 | ||
|     When using :ref:`multi-table inheritance <multi-table-inheritance>`, forms
 | ||
|     generated by a formset factory will contain a parent link field (by default
 | ||
|     ``<parent_model_name>_ptr``) instead of an ``id`` field.
 | ||
| 
 | ||
| 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:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith="O"))
 | ||
| 
 | ||
| Alternatively, you can create a subclass that sets ``self.queryset`` in
 | ||
| ``__init__``::
 | ||
| 
 | ||
|     from django.forms import BaseModelFormSet
 | ||
|     from myapp.models import Author
 | ||
| 
 | ||
| 
 | ||
|     class BaseAuthorFormSet(BaseModelFormSet):
 | ||
|         def __init__(self, *args, **kwargs):
 | ||
|             super().__init__(*args, **kwargs)
 | ||
|             self.queryset = Author.objects.filter(name__startswith="O")
 | ||
| 
 | ||
| Then, pass your ``BaseAuthorFormSet`` class to the factory function:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> AuthorFormSet = modelformset_factory(
 | ||
|     ...     Author, fields=["name", "title"], formset=BaseAuthorFormSet
 | ||
|     ... )
 | ||
| 
 | ||
| If you want to return a formset that doesn't include *any* preexisting
 | ||
| instances of the model, you can specify an empty QuerySet:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|    >>> AuthorFormSet(queryset=Author.objects.none())
 | ||
| 
 | ||
| Changing the form
 | ||
| -----------------
 | ||
| 
 | ||
| By default, when you use ``modelformset_factory``, a model form will
 | ||
| be created using :func:`~django.forms.models.modelform_factory`.
 | ||
| Often, it can be useful to specify a custom model form. For example,
 | ||
| you can create a custom model form that has custom validation::
 | ||
| 
 | ||
|     class AuthorForm(forms.ModelForm):
 | ||
|         class Meta:
 | ||
|             model = Author
 | ||
|             fields = ["name", "title"]
 | ||
| 
 | ||
|         def clean_name(self):
 | ||
|             # custom validation for the name field
 | ||
|             ...
 | ||
| 
 | ||
| Then, pass your model form to the factory function::
 | ||
| 
 | ||
|     AuthorFormSet = modelformset_factory(Author, form=AuthorForm)
 | ||
| 
 | ||
| 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.
 | ||
| 
 | ||
| Specifying widgets to use in the form with ``widgets``
 | ||
| ------------------------------------------------------
 | ||
| 
 | ||
| Using the ``widgets`` parameter, you can specify a dictionary of values to
 | ||
| customize the ``ModelForm``’s widget class for a particular field. This
 | ||
| works the same way as the ``widgets`` dictionary on the inner ``Meta``
 | ||
| class of a ``ModelForm`` works:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> AuthorFormSet = modelformset_factory(
 | ||
|     ...     Author,
 | ||
|     ...     fields=["name", "title"],
 | ||
|     ...     widgets={"name": Textarea(attrs={"cols": 80, "rows": 20})},
 | ||
|     ... )
 | ||
| 
 | ||
| Enabling localization for fields with ``localized_fields``
 | ||
| ----------------------------------------------------------
 | ||
| 
 | ||
| Using the ``localized_fields`` parameter, you can enable localization for
 | ||
| fields in the form.
 | ||
| 
 | ||
|     >>> AuthorFormSet = modelformset_factory(
 | ||
|     ...     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.
 | ||
| 
 | ||
| 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
 | ||
| attached to an existing model instance. If the length of ``initial`` exceeds
 | ||
| the number of extra forms, the excess initial data is ignored. If the extra
 | ||
| forms with initial data aren't changed by the user, they won't be validated or
 | ||
| saved.
 | ||
| 
 | ||
| .. _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:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     # 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 `Selecting the fields to use`_.
 | ||
| 
 | ||
| Pass ``commit=False`` to return the unsaved model instances:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     # 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.
 | ||
| 
 | ||
| After calling ``save()``, your model formset will have three new attributes
 | ||
| containing the formset's changes:
 | ||
| 
 | ||
| .. attribute:: models.BaseModelFormSet.changed_objects
 | ||
| .. attribute:: models.BaseModelFormSet.deleted_objects
 | ||
| .. attribute:: models.BaseModelFormSet.new_objects
 | ||
| 
 | ||
| .. _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:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> Author.objects.order_by("name")
 | ||
|     <QuerySet [<Author: Charles Baudelaire>, <Author: Paul Verlaine>, <Author: Walt Whitman>]>
 | ||
| 
 | ||
|     >>> 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']
 | ||
| 
 | ||
| Also, ``extra=0`` doesn't prevent creation of new model instances as you can
 | ||
| :ref:`add additional forms with JavaScript <understanding-the-managementform>`
 | ||
| or send additional POST data. See :ref:`model-formsets-edit-only` on how to do
 | ||
| this.
 | ||
| 
 | ||
| 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``:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> 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)
 | ||
|     ...
 | ||
|     <div><label for="id_form-0-name">Name:</label><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"></div>
 | ||
|     <div><label for="id_form-1-name">Name:</label><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"></div>
 | ||
|     <div><label for="id_form-2-name">Name:</label><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"></div>
 | ||
|     <div><label for="id_form-3-name">Name:</label><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"></div>
 | ||
| 
 | ||
| A ``max_num`` value of ``None`` (the default) puts a high limit on the number
 | ||
| of forms displayed (1000). In practice this is equivalent to no limit.
 | ||
| 
 | ||
| .. _model-formsets-edit-only:
 | ||
| 
 | ||
| Preventing new objects creation
 | ||
| -------------------------------
 | ||
| 
 | ||
| Using the ``edit_only`` parameter, you can prevent creation of any new
 | ||
| objects:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> AuthorFormSet = modelformset_factory(
 | ||
|     ...     Author,
 | ||
|     ...     fields=["name", "title"],
 | ||
|     ...     edit_only=True,
 | ||
|     ... )
 | ||
| 
 | ||
| Here, the formset will only edit existing ``Author`` instances. No other
 | ||
| objects will be created or edited.
 | ||
| 
 | ||
| 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::
 | ||
| 
 | ||
|     from django.forms import modelformset_factory
 | ||
|     from django.shortcuts import render
 | ||
|     from myapp.models import Author
 | ||
| 
 | ||
| 
 | ||
|     def manage_authors(request):
 | ||
|         AuthorFormSet = modelformset_factory(Author, fields=["name", "title"])
 | ||
|         if request.method == "POST":
 | ||
|             formset = AuthorFormSet(request.POST, request.FILES)
 | ||
|             if formset.is_valid():
 | ||
|                 formset.save()
 | ||
|                 # do something.
 | ||
|         else:
 | ||
|             formset = AuthorFormSet()
 | ||
|         return render(request, "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`.)
 | ||
| 
 | ||
| .. _model-formsets-overriding-clean:
 | ||
| 
 | ||
| Overriding ``clean()`` on a ``ModelFormSet``
 | ||
| --------------------------------------------
 | ||
| 
 | ||
| Just like with ``ModelForms``, by default the ``clean()`` method of a
 | ||
| ``ModelFormSet`` 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 ``ModelFormSet`` and maintain this validation, you must call the parent
 | ||
| class's ``clean`` method::
 | ||
| 
 | ||
|     from django.forms import BaseModelFormSet
 | ||
| 
 | ||
| 
 | ||
|     class MyModelFormSet(BaseModelFormSet):
 | ||
|         def clean(self):
 | ||
|             super().clean()
 | ||
|             # example custom validation across forms in the formset
 | ||
|             for form in self.forms:
 | ||
|                 # your custom formset validation
 | ||
|                 ...
 | ||
| 
 | ||
| Also note that by the time you reach this step, individual model instances
 | ||
| have already been created for each ``Form``. Modifying a value in
 | ||
| ``form.cleaned_data`` is not sufficient to affect the saved value. If you wish
 | ||
| to modify a value in ``ModelFormSet.clean()`` you must modify
 | ||
| ``form.instance``::
 | ||
| 
 | ||
|     from django.forms import BaseModelFormSet
 | ||
| 
 | ||
| 
 | ||
|     class MyModelFormSet(BaseModelFormSet):
 | ||
|         def clean(self):
 | ||
|             super().clean()
 | ||
| 
 | ||
|             for form in self.forms:
 | ||
|                 name = form.cleaned_data["name"].upper()
 | ||
|                 form.cleaned_data["name"] = name
 | ||
|                 # update the instance value.
 | ||
|                 form.instance.name = name
 | ||
| 
 | ||
| Using a custom queryset
 | ||
| -----------------------
 | ||
| 
 | ||
| As stated earlier, you can override the default queryset used by the model
 | ||
| formset::
 | ||
| 
 | ||
|     from django.forms import modelformset_factory
 | ||
|     from django.shortcuts import render
 | ||
|     from myapp.models import Author
 | ||
| 
 | ||
| 
 | ||
|     def manage_authors(request):
 | ||
|         AuthorFormSet = modelformset_factory(Author, fields=["name", "title"])
 | ||
|         queryset = Author.objects.filter(name__startswith="O")
 | ||
|         if request.method == "POST":
 | ||
|             formset = AuthorFormSet(
 | ||
|                 request.POST,
 | ||
|                 request.FILES,
 | ||
|                 queryset=queryset,
 | ||
|             )
 | ||
|             if formset.is_valid():
 | ||
|                 formset.save()
 | ||
|                 # Do something.
 | ||
|         else:
 | ||
|             formset = AuthorFormSet(queryset=queryset)
 | ||
|         return render(request, "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
 | ||
| ---------------------------------
 | ||
| 
 | ||
| There are three ways to render a formset in a Django template.
 | ||
| 
 | ||
| First, you can let the formset do most of the work:
 | ||
| 
 | ||
| .. code-block:: html+django
 | ||
| 
 | ||
|     <form method="post">
 | ||
|         {{ formset }}
 | ||
|     </form>
 | ||
| 
 | ||
| Second, you can manually render the formset, but let the form deal with
 | ||
| itself:
 | ||
| 
 | ||
| .. code-block:: html+django
 | ||
| 
 | ||
|     <form method="post">
 | ||
|         {{ 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:
 | ||
| 
 | ||
| .. code-block:: html+django
 | ||
| 
 | ||
|     <form method="post">
 | ||
|         {{ 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:
 | ||
| 
 | ||
| .. code-block:: html+django
 | ||
| 
 | ||
|     <form method="post">
 | ||
|         {{ 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.)
 | ||
| 
 | ||
| .. _inline-formsets:
 | ||
| 
 | ||
| Inline formsets
 | ||
| ===============
 | ||
| 
 | ||
| .. class:: models.BaseInlineFormSet
 | ||
| 
 | ||
| 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::
 | ||
| 
 | ||
|     from django.db import models
 | ||
| 
 | ||
| 
 | ||
|     class Author(models.Model):
 | ||
|         name = models.CharField(max_length=100)
 | ||
| 
 | ||
| 
 | ||
|     class Book(models.Model):
 | ||
|         author = models.ForeignKey(Author, on_delete=models.CASCADE)
 | ||
|         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:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> from django.forms import inlineformset_factory
 | ||
|     >>> BookFormSet = inlineformset_factory(Author, Book, fields=["title"])
 | ||
|     >>> author = Author.objects.get(name="Mike Royko")
 | ||
|     >>> formset = BookFormSet(instance=author)
 | ||
| 
 | ||
| ``BookFormSet``'s :ref:`prefix <formset-prefix>` is ``'book_set'``
 | ||
| (``<model name>_set`` ). If ``Book``'s ``ForeignKey`` to ``Author`` has a
 | ||
| :attr:`~django.db.models.ForeignKey.related_name`, that's used instead.
 | ||
| 
 | ||
| .. 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>`.
 | ||
| 
 | ||
| Overriding methods on an ``InlineFormSet``
 | ||
| ------------------------------------------
 | ||
| 
 | ||
| When overriding methods on ``InlineFormSet``, you should subclass
 | ||
| :class:`~models.BaseInlineFormSet` rather than
 | ||
| :class:`~models.BaseModelFormSet`.
 | ||
| 
 | ||
| For example, if you want to override ``clean()``::
 | ||
| 
 | ||
|     from django.forms import BaseInlineFormSet
 | ||
| 
 | ||
| 
 | ||
|     class CustomInlineFormSet(BaseInlineFormSet):
 | ||
|         def clean(self):
 | ||
|             super().clean()
 | ||
|             # example custom validation across forms in the formset
 | ||
|             for form in self.forms:
 | ||
|                 # your custom formset validation
 | ||
|                 ...
 | ||
| 
 | ||
| See also :ref:`model-formsets-overriding-clean`.
 | ||
| 
 | ||
| Then when you create your inline formset, pass in the optional argument
 | ||
| ``formset``:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> from django.forms import inlineformset_factory
 | ||
|     >>> BookFormSet = inlineformset_factory(
 | ||
|     ...     Author, Book, fields=["title"], formset=CustomInlineFormSet
 | ||
|     ... )
 | ||
|     >>> author = Author.objects.get(name="Mike Royko")
 | ||
|     >>> formset = BookFormSet(instance=author)
 | ||
| 
 | ||
| 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,
 | ||
|             on_delete=models.CASCADE,
 | ||
|             related_name="from_friends",
 | ||
|         )
 | ||
|         to_friend = models.ForeignKey(
 | ||
|             Friend,
 | ||
|             on_delete=models.CASCADE,
 | ||
|             related_name="friends",
 | ||
|         )
 | ||
|         length_in_months = models.IntegerField()
 | ||
| 
 | ||
| To resolve this, you can use ``fk_name`` to
 | ||
| :func:`~django.forms.models.inlineformset_factory`:
 | ||
| 
 | ||
| .. code-block:: pycon
 | ||
| 
 | ||
|     >>> FriendshipFormSet = inlineformset_factory(
 | ||
|     ...     Friend, Friendship, fk_name="from_friend", fields=["to_friend", "length_in_months"]
 | ||
|     ... )
 | ||
| 
 | ||
| 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, fields=["title"])
 | ||
|         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(request, "manage_books.html", {"formset": formset})
 | ||
| 
 | ||
| Notice how we pass ``instance`` in both the ``POST`` and ``GET`` cases.
 | ||
| 
 | ||
| Specifying widgets to use in the inline form
 | ||
| --------------------------------------------
 | ||
| 
 | ||
| 
 | ||
| ``inlineformset_factory`` uses ``modelformset_factory`` and passes most
 | ||
| of its arguments to ``modelformset_factory``. This means you can use
 | ||
| the ``widgets`` parameter in much the same way as passing it to
 | ||
| ``modelformset_factory``. See `Specifying widgets to use in the form with
 | ||
| widgets`_ above.
 |