1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372 |
- ==========================
- 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.
|