========================== 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 ` 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 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 ` 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-model-errormessages: Considerations regarding model's ``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. 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 `, 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 ``