From fba6c2ede7b25ed8c71a18dede00865dbc5b85af Mon Sep 17 00:00:00 2001 From: Loic Bistuer Date: Wed, 17 Jul 2013 02:27:52 +0700 Subject: [PATCH] Reworked docs for ModelForm validation. --- docs/topics/forms/modelforms.txt | 135 +++++++++++++++++++------------ 1 file changed, 83 insertions(+), 52 deletions(-) diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt index 381a97f25a..0f3c5bb815 100644 --- a/docs/topics/forms/modelforms.txt +++ b/docs/topics/forms/modelforms.txt @@ -197,29 +197,89 @@ we'll discuss in a moment.):: name = forms.CharField(max_length=100) authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all()) -.. _modelform-is-valid-and-errors: +.. _validation-on-modelform: -The ``is_valid()`` method and ``errors`` ----------------------------------------- +Validation on a ``ModelForm`` +----------------------------- -The first time you call ``is_valid()`` or access the ``errors`` attribute of a -``ModelForm`` triggers :ref:`form validation ` as -well as :ref:`model validation `. This has the side-effect -of cleaning the model you pass to the ``ModelForm`` constructor. For instance, -calling ``is_valid()`` on your form will convert any date fields on your model -to actual date objects. If form validation fails, only some of the updates -may be applied. For this reason, you'll probably want to avoid reusing the -model instance passed to the form, especially if validation fails. +There are two main steps involved in validating a ``ModelForm``: +1. :ref:`Validating the form ` +2. :ref:`Validating the model instance ` + +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() +`) 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 bound 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 ` 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 ` 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 ` for more information +on the model's ``clean()`` hook. + +Considerations regarding fields' ``error_messages`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Error messages defined at the +:attr:`form field ` level or at the +:ref:`form Meta ` level always take +precedence over the error messages defined at the +:attr:`model field ` level. +Error messages defined on :attr:`model fields +` are only used when the +``ValidationError`` is raised during the :ref:`model validation +` step and no corresponding error messages are defined at +the form level. The ``save()`` method --------------------- -Every form produced by ``ModelForm`` also has a ``save()`` -method. This method creates and saves a database object from the data -bound to the form. A subclass of ``ModelForm`` can accept an existing -model instance as the keyword argument ``instance``; if this is -supplied, ``save()`` will update that instance. If it's not supplied, +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:: python @@ -240,7 +300,7 @@ supplied, ``save()`` will update that instance. If it's not supplied, >>> f.save() Note that if the form :ref:`hasn't been validated -`, calling ``save()`` will do so by checking +`, 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``. @@ -263,7 +323,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:: python # Create a form instance with POST data. >>> f = AuthorForm(request.POST) @@ -283,7 +345,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 simple ``save()`` on a form, all data -- including many-to-many data -- is saved without the need for any additional method calls. -For example:: +For example: + +.. code-block:: python # Create a form instance with POST data. >>> a = Author() @@ -537,27 +601,6 @@ attribute on the ``Meta`` class. If ``localized_fields`` is set to the special value ``'__all__'``, all fields will be localized. -.. _overriding-modelform-clean-method: - -Overriding the clean() method ------------------------------ - -You can override the ``clean()`` method on a model form to provide additional -validation in the same way you can on a normal form. - -In this regard, model forms have two specific characteristics when compared to -forms: - -By default the ``clean()`` method validates the uniqueness of fields that are -marked as ``unique``, ``unique_together`` or ``unique_for_date|month|year`` on -the model. Therefore, if you would like to override the ``clean()`` method and -maintain the default validation, you must call the parent class's ``clean()`` -method. - -Also, a model form instance bound to a model object will contain a -``self.instance`` attribute that gives model form methods access to that -specific model instance. - Form inheritance ---------------- @@ -596,18 +639,6 @@ There are a couple of things to note, however. Chances are these notes won't affect you unless you're trying to do something tricky with subclassing. -Interaction with model validation ---------------------------------- - -As part of its validation process, ``ModelForm`` will call the ``clean()`` -method of each field on your model that has a corresponding field on your form. -If you have excluded any model fields, validation will not be run on those -fields. See the :doc:`form validation ` documentation -for more on how field cleaning and validation work. Also, your model's -``clean()`` method will be called before any uniqueness checks are made. See -:ref:`Validating objects ` for more information on the -model's ``clean()`` hook. - .. _modelforms-factory: ModelForm factory function