mirror of
https://github.com/django/django.git
synced 2025-10-24 06:06:09 +00:00
[4.2.x] Refs #34140 -- Applied rst code-block to non-Python examples.
Thanks to J.V. Zammit, Paolo Melchiorre, and Mariusz Felisiak for
reviews.
Backport of 534ac48297 from main.
This commit is contained in:
committed by
Mariusz Felisiak
parent
4a89aa25c9
commit
b784768eef
@@ -8,7 +8,9 @@ Formsets
|
||||
|
||||
A formset is a layer of abstraction to work with multiple forms on the same
|
||||
page. It can be best compared to a data grid. Let's say you have the following
|
||||
form::
|
||||
form:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django import forms
|
||||
>>> class ArticleForm(forms.Form):
|
||||
@@ -16,14 +18,18 @@ form::
|
||||
... pub_date = forms.DateField()
|
||||
|
||||
You might want to allow the user to create several articles at once. To create
|
||||
a formset out of an ``ArticleForm`` you would do::
|
||||
a formset out of an ``ArticleForm`` you would do:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import formset_factory
|
||||
>>> ArticleFormSet = formset_factory(ArticleForm)
|
||||
|
||||
You now have created a formset class named ``ArticleFormSet``.
|
||||
Instantiating the formset gives you the ability to iterate over the forms
|
||||
in the formset and display them as you would with a regular form::
|
||||
in the formset and display them as you would with a regular form:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> formset = ArticleFormSet()
|
||||
>>> for form in formset:
|
||||
@@ -34,7 +40,9 @@ in the formset and display them as you would with a regular form::
|
||||
As you can see it only displayed one empty form. The number of empty forms
|
||||
that is displayed is controlled by the ``extra`` parameter. By default,
|
||||
:func:`~django.forms.formsets.formset_factory` defines one extra form; the
|
||||
following example will create a formset class to display two blank forms::
|
||||
following example will create a formset class to display two blank forms:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
|
||||
|
||||
@@ -55,7 +63,9 @@ Initial data is what drives the main usability of a formset. As shown above
|
||||
you can define the number of extra forms. What this means is that you are
|
||||
telling the formset how many additional forms to show in addition to the
|
||||
number of forms it generates from the initial data. Let's take a look at an
|
||||
example::
|
||||
example:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import datetime
|
||||
>>> from django.forms import formset_factory
|
||||
@@ -94,7 +104,9 @@ Limiting the maximum number of forms
|
||||
====================================
|
||||
|
||||
The ``max_num`` parameter to :func:`~django.forms.formsets.formset_factory`
|
||||
gives you the ability to limit the number of forms the formset will display::
|
||||
gives you the ability to limit the number of forms the formset will display:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import formset_factory
|
||||
>>> from myapp.forms import ArticleForm
|
||||
@@ -133,7 +145,9 @@ Limiting the maximum number of instantiated forms
|
||||
|
||||
The ``absolute_max`` parameter to :func:`.formset_factory` allows limiting the
|
||||
number of forms that can be instantiated when supplying ``POST`` data. This
|
||||
protects against memory exhaustion attacks using forged ``POST`` requests::
|
||||
protects against memory exhaustion attacks using forged ``POST`` requests:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms.formsets import formset_factory
|
||||
>>> from myapp.forms import ArticleForm
|
||||
@@ -160,7 +174,9 @@ Formset validation
|
||||
|
||||
Validation with a formset is almost identical to a regular ``Form``. There is
|
||||
an ``is_valid`` method on the formset to provide a convenient way to validate
|
||||
all forms in the formset::
|
||||
all forms in the formset:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import formset_factory
|
||||
>>> from myapp.forms import ArticleForm
|
||||
@@ -175,7 +191,9 @@ all forms in the formset::
|
||||
|
||||
We passed in no data to the formset which is resulting in a valid form. The
|
||||
formset is smart enough to ignore extra forms that were not changed. If we
|
||||
provide an invalid article::
|
||||
provide an invalid article:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> data = {
|
||||
... 'form-TOTAL_FORMS': '2',
|
||||
@@ -203,7 +221,9 @@ validation may be incorrect when adding and deleting forms.
|
||||
.. method:: BaseFormSet.total_error_count()
|
||||
|
||||
To check how many errors there are in the formset, we can use the
|
||||
``total_error_count`` method::
|
||||
``total_error_count`` method:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> # Using the previous example
|
||||
>>> formset.errors
|
||||
@@ -214,7 +234,9 @@ To check how many errors there are in the formset, we can use the
|
||||
1
|
||||
|
||||
We can also check if form data differs from the initial data (i.e. the form was
|
||||
sent without any data)::
|
||||
sent without any data):
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> data = {
|
||||
... 'form-TOTAL_FORMS': '1',
|
||||
@@ -235,7 +257,9 @@ You may have noticed the additional data (``form-TOTAL_FORMS``,
|
||||
``form-INITIAL_FORMS``) that was required in the formset's data above. This
|
||||
data is required for the ``ManagementForm``. This form is used by the formset
|
||||
to manage the collection of forms contained in the formset. If you don't
|
||||
provide this management data, the formset will be invalid::
|
||||
provide this management data, the formset will be invalid:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> data = {
|
||||
... 'form-0-title': 'Test',
|
||||
@@ -301,7 +325,9 @@ you want to override. Error message keys include ``'too_few_forms'``,
|
||||
respectively.
|
||||
|
||||
For example, here is the default error message when the
|
||||
management form is missing::
|
||||
management form is missing:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> formset = ArticleFormSet({})
|
||||
>>> formset.is_valid()
|
||||
@@ -309,7 +335,9 @@ management form is missing::
|
||||
>>> formset.non_form_errors()
|
||||
['ManagementForm data is missing or has been tampered with. Missing fields: form-TOTAL_FORMS, form-INITIAL_FORMS. You may need to file a bug report if the issue persists.']
|
||||
|
||||
And here is a custom error message::
|
||||
And here is a custom error message:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> formset = ArticleFormSet({}, error_messages={'missing_management_form': 'Sorry, something went wrong.'})
|
||||
>>> formset.is_valid()
|
||||
@@ -325,7 +353,9 @@ Custom formset validation
|
||||
-------------------------
|
||||
|
||||
A formset has a ``clean`` method similar to the one on a ``Form`` class. This
|
||||
is where you define your own validation that works at the formset level::
|
||||
is where you define your own validation that works at the formset level:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.core.exceptions import ValidationError
|
||||
>>> from django.forms import BaseFormSet
|
||||
@@ -479,7 +509,9 @@ formsets and deletion of forms from a formset.
|
||||
|
||||
Default: ``False``
|
||||
|
||||
Lets you create a formset with the ability to order::
|
||||
Lets you create a formset with the ability to order:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import formset_factory
|
||||
>>> from myapp.forms import ArticleForm
|
||||
@@ -503,7 +535,9 @@ Lets you create a formset with the ability to order::
|
||||
This adds an additional field to each form. This new field is named ``ORDER``
|
||||
and is an ``forms.IntegerField``. For the forms that came from the initial
|
||||
data it automatically assigned them a numeric value. Let's look at what will
|
||||
happen when the user changes these values::
|
||||
happen when the user changes these values:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> data = {
|
||||
... 'form-TOTAL_FORMS': '3',
|
||||
@@ -545,7 +579,9 @@ control the widget used with
|
||||
Default: :class:`~django.forms.NumberInput`
|
||||
|
||||
Set ``ordering_widget`` to specify the widget class to be used with
|
||||
``can_order``::
|
||||
``can_order``:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import BaseFormSet, formset_factory
|
||||
>>> from myapp.forms import ArticleForm
|
||||
@@ -560,7 +596,9 @@ Set ``ordering_widget`` to specify the widget class to be used with
|
||||
.. method:: BaseFormSet.get_ordering_widget()
|
||||
|
||||
Override ``get_ordering_widget()`` if you need to provide a widget instance for
|
||||
use with ``can_order``::
|
||||
use with ``can_order``:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import BaseFormSet, formset_factory
|
||||
>>> from myapp.forms import ArticleForm
|
||||
@@ -577,7 +615,9 @@ use with ``can_order``::
|
||||
|
||||
Default: ``False``
|
||||
|
||||
Lets you create a formset with the ability to select forms for deletion::
|
||||
Lets you create a formset with the ability to select forms for deletion:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import formset_factory
|
||||
>>> from myapp.forms import ArticleForm
|
||||
@@ -600,7 +640,9 @@ Lets you create a formset with the ability to select forms for deletion::
|
||||
|
||||
Similar to ``can_order`` this adds a new field to each form named ``DELETE``
|
||||
and is a ``forms.BooleanField``. When data comes through marking any of the
|
||||
delete fields you can access them with ``deleted_forms``::
|
||||
delete fields you can access them with ``deleted_forms``:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> data = {
|
||||
... 'form-TOTAL_FORMS': '3',
|
||||
@@ -631,7 +673,9 @@ If you call ``formset.save(commit=False)``, objects will not be deleted
|
||||
automatically. You'll need to call ``delete()`` on each of the
|
||||
:attr:`formset.deleted_objects
|
||||
<django.forms.models.BaseModelFormSet.deleted_objects>` to actually delete
|
||||
them::
|
||||
them:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> instances = formset.save(commit=False)
|
||||
>>> for obj in formset.deleted_objects:
|
||||
@@ -655,7 +699,9 @@ control the widget used with
|
||||
Default: :class:`~django.forms.CheckboxInput`
|
||||
|
||||
Set ``deletion_widget`` to specify the widget class to be used with
|
||||
``can_delete``::
|
||||
``can_delete``:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import BaseFormSet, formset_factory
|
||||
>>> from myapp.forms import ArticleForm
|
||||
@@ -670,7 +716,9 @@ Set ``deletion_widget`` to specify the widget class to be used with
|
||||
.. method:: BaseFormSet.get_deletion_widget()
|
||||
|
||||
Override ``get_deletion_widget()`` if you need to provide a widget instance for
|
||||
use with ``can_delete``::
|
||||
use with ``can_delete``:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import BaseFormSet, formset_factory
|
||||
>>> from myapp.forms import ArticleForm
|
||||
@@ -696,7 +744,9 @@ Adding additional fields to a formset
|
||||
If you need to add additional fields to the formset this can be easily
|
||||
accomplished. The formset base class provides an ``add_fields`` method. You
|
||||
can override this method to add your own fields or even redefine the default
|
||||
fields/attributes of the order and deletion fields::
|
||||
fields/attributes of the order and deletion fields:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import BaseFormSet
|
||||
>>> from django.forms import formset_factory
|
||||
@@ -720,7 +770,9 @@ Passing custom parameters to formset forms
|
||||
==========================================
|
||||
|
||||
Sometimes your form class takes custom parameters, like ``MyArticleForm``.
|
||||
You can pass this parameter when instantiating the formset::
|
||||
You can pass this parameter when instantiating the formset:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import BaseFormSet
|
||||
>>> from django.forms import formset_factory
|
||||
@@ -737,7 +789,9 @@ You can pass this parameter when instantiating the formset::
|
||||
The ``form_kwargs`` may also depend on the specific form instance. The formset
|
||||
base class provides a ``get_form_kwargs`` method. The method takes a single
|
||||
argument - the index of the form in the formset. The index is ``None`` for the
|
||||
:ref:`empty_form`::
|
||||
:ref:`empty_form`:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import BaseFormSet
|
||||
>>> from django.forms import formset_factory
|
||||
|
||||
@@ -748,7 +748,9 @@ Useful attributes on ``{{ field }}`` include:
|
||||
``{{ field.label_tag }}``
|
||||
The field's label wrapped in the appropriate HTML ``<label>`` tag. This
|
||||
includes the form's :attr:`~django.forms.Form.label_suffix`. For example,
|
||||
the default ``label_suffix`` is a colon::
|
||||
the default ``label_suffix`` is a colon:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
<label for="id_email">Email address:</label>
|
||||
|
||||
|
||||
@@ -67,7 +67,9 @@ to include the CSS file ``pretty.css``, and the JavaScript files
|
||||
|
||||
This static definition is converted at runtime into a widget property
|
||||
named ``media``. The list of assets for a ``CalendarWidget`` instance
|
||||
can be retrieved through this property::
|
||||
can be retrieved through this property:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> w = CalendarWidget()
|
||||
>>> print(w.media)
|
||||
@@ -112,7 +114,9 @@ requirements::
|
||||
'print': ['newspaper.css],
|
||||
}
|
||||
|
||||
If this last CSS definition were to be rendered, it would become the following HTML::
|
||||
If this last CSS definition were to be rendered, it would become the following HTML:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
<link href="http://static.example.com/pretty.css" media="screen" rel="stylesheet">
|
||||
<link href="http://static.example.com/lo_res.css" media="tv,projector" rel="stylesheet">
|
||||
@@ -139,7 +143,9 @@ By default, any object using a static ``Media`` definition will
|
||||
inherit all the assets associated with the parent widget. This occurs
|
||||
regardless of how the parent defines its own requirements. For
|
||||
example, if we were to extend our basic Calendar widget from the
|
||||
example above::
|
||||
example above:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> class FancyCalendarWidget(CalendarWidget):
|
||||
... class Media:
|
||||
@@ -158,7 +164,9 @@ example above::
|
||||
|
||||
The FancyCalendar widget inherits all the assets from its parent
|
||||
widget. If you don't want ``Media`` to be inherited in this way, add
|
||||
an ``extend=False`` declaration to the ``Media`` declaration::
|
||||
an ``extend=False`` declaration to the ``Media`` declaration:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> class FancyCalendarWidget(CalendarWidget):
|
||||
... class Media:
|
||||
@@ -224,7 +232,9 @@ To find the appropriate prefix to use, Django will check if the
|
||||
:setting:`STATIC_URL` setting is not ``None`` and automatically fall back
|
||||
to using :setting:`MEDIA_URL`. For example, if the :setting:`MEDIA_URL` for
|
||||
your site was ``'http://uploads.example.com/'`` and :setting:`STATIC_URL`
|
||||
was ``None``::
|
||||
was ``None``:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django import forms
|
||||
>>> class CalendarWidget(forms.TextInput):
|
||||
@@ -240,7 +250,9 @@ was ``None``::
|
||||
<script src="http://uploads.example.com/animations.js"></script>
|
||||
<script src="http://othersite.com/actions.js"></script>
|
||||
|
||||
But if :setting:`STATIC_URL` is ``'http://static.example.com/'``::
|
||||
But if :setting:`STATIC_URL` is ``'http://static.example.com/'``:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> w = CalendarWidget()
|
||||
>>> print(w.media)
|
||||
@@ -249,7 +261,9 @@ But if :setting:`STATIC_URL` is ``'http://static.example.com/'``::
|
||||
<script src="http://othersite.com/actions.js"></script>
|
||||
|
||||
Or if :mod:`~django.contrib.staticfiles` is configured using the
|
||||
:class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage`::
|
||||
:class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage`:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> w = CalendarWidget()
|
||||
>>> print(w.media)
|
||||
@@ -265,7 +279,9 @@ Paths as objects
|
||||
Asset paths may also be given as hashable objects implementing an
|
||||
``__html__()`` method. The ``__html__()`` method is typically added using the
|
||||
:func:`~django.utils.html.html_safe` decorator. The object is responsible for
|
||||
outputting the complete HTML ``<script>`` or ``<link>`` tag content::
|
||||
outputting the complete HTML ``<script>`` or ``<link>`` tag content:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django import forms
|
||||
>>> from django.utils.html import html_safe
|
||||
@@ -294,7 +310,9 @@ Subsets of assets
|
||||
-----------------
|
||||
|
||||
If you only want files of a particular type, you can use the subscript
|
||||
operator to filter out a medium of interest. For example::
|
||||
operator to filter out a medium of interest. For example:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> w = CalendarWidget()
|
||||
>>> print(w.media)
|
||||
@@ -313,7 +331,9 @@ Combining ``Media`` objects
|
||||
|
||||
``Media`` objects can also be added together. When two ``Media`` objects are
|
||||
added, the resulting ``Media`` object contains the union of the assets
|
||||
specified by both::
|
||||
specified by both:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django import forms
|
||||
>>> class CalendarWidget(forms.TextInput):
|
||||
@@ -345,7 +365,9 @@ example, you may have a script that depends on jQuery. Therefore, combining
|
||||
``Media`` objects attempts to preserve the relative order in which assets are
|
||||
defined in each ``Media`` class.
|
||||
|
||||
For example::
|
||||
For example:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django import forms
|
||||
>>> class CalendarWidget(forms.TextInput):
|
||||
@@ -377,7 +399,9 @@ are exactly the same.
|
||||
Regardless of whether you define a ``media`` declaration, *all* Form
|
||||
objects have a ``media`` property. The default value for this property
|
||||
is the result of adding the ``media`` definitions for all widgets that
|
||||
are part of the form::
|
||||
are part of the form:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django import forms
|
||||
>>> class ContactForm(forms.Form):
|
||||
@@ -392,7 +416,9 @@ are part of the form::
|
||||
<script src="http://static.example.com/whizbang.js"></script>
|
||||
|
||||
If you want to associate additional assets with a form -- for example,
|
||||
CSS for form layout -- add a ``Media`` declaration to the form::
|
||||
CSS for form layout -- add a ``Media`` declaration to the form:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> class ContactForm(forms.Form):
|
||||
... date = DateField(widget=CalendarWidget)
|
||||
|
||||
@@ -17,7 +17,9 @@ 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::
|
||||
For example:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import ModelForm
|
||||
>>> from myapp.models import Article
|
||||
@@ -320,7 +322,9 @@ 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::
|
||||
``save()`` will create a new instance of the specified model:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from myapp.models import Article
|
||||
>>> from myapp.forms import ArticleForm
|
||||
@@ -373,7 +377,9 @@ 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::
|
||||
``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)
|
||||
@@ -392,7 +398,9 @@ you've manually saved the instance produced by the form, you can invoke
|
||||
|
||||
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::
|
||||
is saved without the need for any additional method calls. For example:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
# Create a form instance with POST data.
|
||||
>>> a = Author()
|
||||
@@ -680,7 +688,9 @@ 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::
|
||||
using the previous ``ArticleForm`` class:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> class EnhancedArticleForm(ArticleForm):
|
||||
... def clean_pub_date(self):
|
||||
@@ -690,7 +700,9 @@ 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::
|
||||
the ``Meta.fields`` or ``Meta.exclude`` lists:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> class RestrictedArticleForm(EnhancedArticleForm):
|
||||
... class Meta(ArticleForm.Meta):
|
||||
@@ -725,7 +737,9 @@ 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::
|
||||
and values from an attached model instance. For example:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> article = Article.objects.get(pk=1)
|
||||
>>> article.headline
|
||||
@@ -742,14 +756,18 @@ 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::
|
||||
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::
|
||||
specifying the widgets to be used for a given field:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import Textarea
|
||||
>>> Form = modelform_factory(Book, form=BookForm,
|
||||
@@ -773,7 +791,9 @@ Model formsets
|
||||
|
||||
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::
|
||||
convenient. Let's reuse the ``Author`` model from above:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import modelformset_factory
|
||||
>>> from myapp.models import Author
|
||||
@@ -781,12 +801,16 @@ convenient. Let's reuse the ``Author`` model from above::
|
||||
|
||||
Using ``fields`` restricts the formset to use only the given fields.
|
||||
Alternatively, you can take an "opt-out" approach, specifying which fields to
|
||||
exclude::
|
||||
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::
|
||||
with the ``Author`` model. It works just like a regular formset:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> formset = AuthorFormSet()
|
||||
>>> print(formset)
|
||||
@@ -818,7 +842,9 @@ 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::
|
||||
``queryset`` argument:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
|
||||
|
||||
@@ -833,13 +859,17 @@ Alternatively, you can create a subclass that sets ``self.queryset`` in
|
||||
super().__init__(*args, **kwargs)
|
||||
self.queryset = Author.objects.filter(name__startswith='O')
|
||||
|
||||
Then, pass your ``BaseAuthorFormSet`` class to the factory function::
|
||||
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::
|
||||
instances of the model, you can specify an empty QuerySet:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> AuthorFormSet(queryset=Author.objects.none())
|
||||
|
||||
@@ -874,7 +904,9 @@ 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::
|
||||
class of a ``ModelForm`` works:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> AuthorFormSet = modelformset_factory(
|
||||
... Author, fields=['name', 'title'],
|
||||
@@ -912,7 +944,9 @@ 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::
|
||||
with the formset's ``save()`` method:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
# Create a formset instance with POST data.
|
||||
>>> formset = AuthorFormSet(request.POST)
|
||||
@@ -930,7 +964,9 @@ 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::
|
||||
Pass ``commit=False`` to return the unsaved model instances:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
# don't save to the database
|
||||
>>> instances = formset.save(commit=False)
|
||||
@@ -959,7 +995,9 @@ 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::
|
||||
``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>]>
|
||||
@@ -976,7 +1014,9 @@ 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``::
|
||||
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'))
|
||||
@@ -998,7 +1038,9 @@ Preventing new objects creation
|
||||
.. versionadded:: 4.1
|
||||
|
||||
Using the ``edit_only`` parameter, you can prevent creation of any new
|
||||
objects::
|
||||
objects:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> AuthorFormSet = modelformset_factory(
|
||||
... Author,
|
||||
@@ -1106,18 +1148,20 @@ 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::
|
||||
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::
|
||||
itself:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
<form method="post">
|
||||
{{ formset.management_form }}
|
||||
@@ -1130,7 +1174,9 @@ 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::
|
||||
Third, you can manually render each field:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
<form method="post">
|
||||
{{ formset.management_form }}
|
||||
@@ -1143,7 +1189,9 @@ Third, you can manually render each field::
|
||||
|
||||
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::
|
||||
if you were rendering the ``name`` and ``age`` fields of a model:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
<form method="post">
|
||||
{{ formset.management_form }}
|
||||
@@ -1161,8 +1209,6 @@ 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
|
||||
@@ -1184,7 +1230,9 @@ you have these two models::
|
||||
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::
|
||||
a particular author, you could do this:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import inlineformset_factory
|
||||
>>> BookFormSet = inlineformset_factory(Author, Book, fields=['title'])
|
||||
@@ -1227,7 +1275,9 @@ For example, if you want to override ``clean()``::
|
||||
See also :ref:`model-formsets-overriding-clean`.
|
||||
|
||||
Then when you create your inline formset, pass in the optional argument
|
||||
``formset``::
|
||||
``formset``:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> from django.forms import inlineformset_factory
|
||||
>>> BookFormSet = inlineformset_factory(Author, Book, fields=['title'],
|
||||
@@ -1256,7 +1306,9 @@ the following model::
|
||||
length_in_months = models.IntegerField()
|
||||
|
||||
To resolve this, you can use ``fk_name`` to
|
||||
:func:`~django.forms.models.inlineformset_factory`::
|
||||
:func:`~django.forms.models.inlineformset_factory`:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> FriendshipFormSet = inlineformset_factory(Friend, Friendship, fk_name='from_friend',
|
||||
... fields=['to_friend', 'length_in_months'])
|
||||
|
||||
Reference in New Issue
Block a user