2008-08-24 00:25:40 +02:00
|
|
|
.. _topics-forms-modelforms:
|
|
|
|
|
|
|
|
==========================
|
|
|
|
Creating forms from models
|
|
|
|
==========================
|
2007-12-02 20:29:54 +01:00
|
|
|
|
|
|
|
``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 let you create a ``Form``
|
|
|
|
class from a Django model.
|
|
|
|
|
|
|
|
For example::
|
|
|
|
|
2008-07-21 18:38:54 +02:00
|
|
|
>>> from django.forms import ModelForm
|
2008-01-28 04:12:28 +01:00
|
|
|
|
2007-12-02 20:29:54 +01:00
|
|
|
# Create the form class.
|
|
|
|
>>> class ArticleForm(ModelForm):
|
|
|
|
... class Meta:
|
|
|
|
... model = Article
|
|
|
|
|
|
|
|
# Creating a form to add an article.
|
2007-12-13 03:48:04 +01:00
|
|
|
>>> form = ArticleForm()
|
2007-12-02 20:29:54 +01:00
|
|
|
|
|
|
|
# Creating a form to change an existing article.
|
|
|
|
>>> article = Article.objects.get(pk=1)
|
2007-12-13 03:48:04 +01:00
|
|
|
>>> form = ArticleForm(instance=article)
|
2007-12-02 20:29:54 +01:00
|
|
|
|
|
|
|
Field types
|
|
|
|
-----------
|
|
|
|
|
|
|
|
The generated ``Form`` class will have a form field for every model field. 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:
|
|
|
|
|
|
|
|
=============================== ========================================
|
|
|
|
Model field Form field
|
|
|
|
=============================== ========================================
|
|
|
|
``AutoField`` Not represented in the form
|
|
|
|
``BooleanField`` ``BooleanField``
|
|
|
|
``CharField`` ``CharField`` with ``max_length`` set to
|
|
|
|
the model field's ``max_length``
|
|
|
|
``CommaSeparatedIntegerField`` ``CharField``
|
|
|
|
``DateField`` ``DateField``
|
|
|
|
``DateTimeField`` ``DateTimeField``
|
|
|
|
``DecimalField`` ``DecimalField``
|
|
|
|
``EmailField`` ``EmailField``
|
|
|
|
``FileField`` ``FileField``
|
|
|
|
``FilePathField`` ``CharField``
|
|
|
|
``FloatField`` ``FloatField``
|
|
|
|
``ForeignKey`` ``ModelChoiceField`` (see below)
|
|
|
|
``ImageField`` ``ImageField``
|
|
|
|
``IntegerField`` ``IntegerField``
|
|
|
|
``IPAddressField`` ``IPAddressField``
|
|
|
|
``ManyToManyField`` ``ModelMultipleChoiceField`` (see
|
|
|
|
below)
|
|
|
|
``NullBooleanField`` ``CharField``
|
|
|
|
``PhoneNumberField`` ``USPhoneNumberField``
|
|
|
|
(from ``django.contrib.localflavor.us``)
|
|
|
|
``PositiveIntegerField`` ``IntegerField``
|
|
|
|
``PositiveSmallIntegerField`` ``IntegerField``
|
Removed oldforms, validators, and related code:
* Removed `Manipulator`, `AutomaticManipulator`, and related classes.
* Removed oldforms specific bits from model fields:
* Removed `validator_list` and `core` arguments from constructors.
* Removed the methods:
* `get_manipulator_field_names`
* `get_manipulator_field_objs`
* `get_manipulator_fields`
* `get_manipulator_new_data`
* `prepare_field_objs_and_params`
* `get_follow`
* Renamed `flatten_data` method to `value_to_string` for better alignment with its use by the serialization framework, which was the only remaining code using `flatten_data`.
* Removed oldforms methods from `django.db.models.Options` class: `get_followed_related_objects`, `get_data_holders`, `get_follow`, and `has_field_type`.
* Removed oldforms-admin specific options from `django.db.models.fields.related` classes: `num_in_admin`, `min_num_in_admin`, `max_num_in_admin`, `num_extra_on_change`, and `edit_inline`.
* Serialization framework
* `Serializer.get_string_value` now calls the model fields' renamed `value_to_string` methods.
* Removed a special-casing of `models.DateTimeField` in `core.serializers.base.Serializer.get_string_value` that's handled by `django.db.models.fields.DateTimeField.value_to_string`.
* Removed `django.core.validators`:
* Moved `ValidationError` exception to `django.core.exceptions`.
* For the couple places that were using validators, brought over the necessary code to maintain the same functionality.
* Introduced a SlugField form field for validation and to compliment the SlugField model field (refs #8040).
* Removed an oldforms-style model creation hack (refs #2160).
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-08-27 09:19:44 +02:00
|
|
|
``SlugField`` ``SlugField``
|
2007-12-02 20:29:54 +01:00
|
|
|
``SmallIntegerField`` ``IntegerField``
|
|
|
|
``TextField`` ``CharField`` with ``widget=Textarea``
|
|
|
|
``TimeField`` ``TimeField``
|
|
|
|
``URLField`` ``URLField`` with ``verify_exists`` set
|
|
|
|
to the model field's ``verify_exists``
|
|
|
|
``XMLField`` ``CharField`` with ``widget=Textarea``
|
|
|
|
=============================== ========================================
|
|
|
|
|
|
|
|
|
2008-11-15 06:51:25 +01:00
|
|
|
.. versionadded:: 1.0
|
2007-12-02 20:29:54 +01:00
|
|
|
The ``FloatField`` form field and ``DecimalField`` model and form fields
|
2008-11-15 06:51:25 +01:00
|
|
|
are new in Django 1.0.
|
2007-12-02 20:29:54 +01:00
|
|
|
|
|
|
|
As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field
|
|
|
|
types are special cases:
|
|
|
|
|
2008-07-21 18:38:54 +02:00
|
|
|
* ``ForeignKey`` is represented by ``django.forms.ModelChoiceField``,
|
2007-12-02 20:29:54 +01:00
|
|
|
which is a ``ChoiceField`` whose choices are a model ``QuerySet``.
|
|
|
|
|
|
|
|
* ``ManyToManyField`` is represented by
|
2008-07-21 18:38:54 +02:00
|
|
|
``django.forms.ModelMultipleChoiceField``, which is a
|
2007-12-02 20:29:54 +01:00
|
|
|
``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
|
2008-01-28 03:51:40 +01:00
|
|
|
field. See `Overriding the default field types`_ below.
|
2007-12-02 20:29:54 +01:00
|
|
|
|
|
|
|
A full example
|
|
|
|
--------------
|
|
|
|
|
|
|
|
Consider this set of models::
|
|
|
|
|
|
|
|
from django.db import models
|
2008-07-21 18:38:54 +02:00
|
|
|
from django.forms import ModelForm
|
2007-12-02 20:29:54 +01:00
|
|
|
|
|
|
|
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 __unicode__(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
|
|
|
|
|
|
|
|
class BookForm(ModelForm):
|
|
|
|
class Meta:
|
|
|
|
model = Book
|
|
|
|
|
|
|
|
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.)::
|
|
|
|
|
|
|
|
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())
|
|
|
|
|
|
|
|
The ``save()`` method
|
|
|
|
---------------------
|
|
|
|
|
2007-12-13 03:48:04 +01:00
|
|
|
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,
|
|
|
|
``save()`` will create a new instance of the specified model::
|
2007-12-02 20:29:54 +01:00
|
|
|
|
|
|
|
# Create a form instance from POST data.
|
2007-12-13 03:48:04 +01:00
|
|
|
>>> f = ArticleForm(request.POST)
|
2007-12-02 20:29:54 +01:00
|
|
|
|
|
|
|
# Save a new Article object from the form's data.
|
|
|
|
>>> new_article = f.save()
|
|
|
|
|
2007-12-13 03:48:04 +01:00
|
|
|
# Create a form to edit an existing Article.
|
|
|
|
>>> a = Article.objects.get(pk=1)
|
|
|
|
>>> f = ArticleForm(instance=a)
|
2008-06-23 14:57:11 +02:00
|
|
|
>>> 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()
|
2007-12-13 03:48:04 +01:00
|
|
|
|
2007-12-02 20:29:54 +01:00
|
|
|
Note that ``save()`` will raise a ``ValueError`` if the data in the form
|
|
|
|
doesn't validate -- i.e., ``if form.errors``.
|
|
|
|
|
|
|
|
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
|
2008-12-02 05:07:43 +01:00
|
|
|
object before saving it, or if you want to use on of the specialised
|
|
|
|
:ref:`model saving options <ref-models-force-insert>`. ``commit`` is ``True`` by default.
|
2007-12-02 20:29:54 +01:00
|
|
|
|
|
|
|
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::
|
|
|
|
|
|
|
|
# Create a form instance with POST data.
|
2007-12-13 03:48:04 +01:00
|
|
|
>>> f = AuthorForm(request.POST)
|
2007-12-02 20:29:54 +01:00
|
|
|
|
|
|
|
# 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 simple ``save()`` on a form, all data -- including
|
|
|
|
many-to-many data -- is saved without the need for any additional method calls.
|
|
|
|
For example::
|
|
|
|
|
|
|
|
# Create a form instance with POST data.
|
|
|
|
>>> a = Author()
|
2008-03-11 07:40:50 +01:00
|
|
|
>>> f = AuthorForm(request.POST, instance=a)
|
2007-12-02 20:29:54 +01:00
|
|
|
|
|
|
|
# Create and save the new author instance. There's no need to do anything else.
|
|
|
|
>>> new_author = f.save()
|
|
|
|
|
2008-08-24 00:25:40 +02:00
|
|
|
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:`topics-forms-index` for more information.
|
2008-03-18 22:13:12 +01:00
|
|
|
|
2007-12-02 20:29:54 +01:00
|
|
|
Using a subset of fields on the form
|
|
|
|
------------------------------------
|
|
|
|
|
|
|
|
In some cases, you may not want all the model fields to appear on the generated
|
|
|
|
form. There are three ways of telling ``ModelForm`` to use only a subset of the
|
|
|
|
model fields:
|
|
|
|
|
2008-03-11 07:40:50 +01:00
|
|
|
1. Set ``editable=False`` on the model field. As a result, *any* form
|
|
|
|
created from the model via ``ModelForm`` will not include that
|
|
|
|
field.
|
2007-12-02 20:29:54 +01:00
|
|
|
|
2008-03-11 07:40:50 +01:00
|
|
|
2. Use the ``fields`` attribute of the ``ModelForm``'s inner ``Meta``
|
|
|
|
class. This attribute, if given, should be a list of field names
|
|
|
|
to include in the form.
|
2007-12-02 20:29:54 +01:00
|
|
|
|
2008-03-11 07:40:50 +01:00
|
|
|
3. Use the ``exclude`` attribute of the ``ModelForm``'s inner ``Meta``
|
|
|
|
class. This attribute, if given, should be a list of field names
|
2008-03-11 07:49:36 +01:00
|
|
|
to exclude from the form.
|
2007-12-02 20:29:54 +01:00
|
|
|
|
2008-03-11 07:40:50 +01:00
|
|
|
For example, if you want a form for the ``Author`` model (defined
|
|
|
|
above) that includes only the ``name`` and ``title`` fields, you would
|
|
|
|
specify ``fields`` or ``exclude`` like this::
|
2007-12-02 20:29:54 +01:00
|
|
|
|
2008-03-11 07:40:50 +01:00
|
|
|
class PartialAuthorForm(ModelForm):
|
|
|
|
class Meta:
|
|
|
|
model = Author
|
|
|
|
fields = ('name', 'title')
|
|
|
|
|
|
|
|
class PartialAuthorForm(ModelForm):
|
|
|
|
class Meta:
|
|
|
|
model = Author
|
|
|
|
exclude = ('birth_date',)
|
2007-12-02 20:29:54 +01:00
|
|
|
|
2008-03-11 07:40:50 +01:00
|
|
|
Since the Author model has only 3 fields, 'name', 'title', and
|
|
|
|
'birth_date', the forms above will contain exactly the same fields.
|
2007-12-02 20:29:54 +01:00
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
If you specify ``fields`` or ``exclude`` when creating a form with
|
|
|
|
``ModelForm``, then the fields that are not in the resulting form will not
|
|
|
|
be set by the form's ``save()`` method. 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, or use ``save(commit=False)`` and
|
2007-12-19 04:39:21 +01:00
|
|
|
manually set any extra required fields::
|
2008-01-28 04:12:28 +01:00
|
|
|
|
2007-12-03 17:18:23 +01:00
|
|
|
instance = Instance(required_field='value')
|
2007-12-13 03:48:04 +01:00
|
|
|
form = InstanceForm(request.POST, instance=instance)
|
2007-12-02 20:29:54 +01:00
|
|
|
new_instance = form.save()
|
|
|
|
|
|
|
|
instance = form.save(commit=False)
|
|
|
|
instance.required_field = 'new value'
|
|
|
|
new_instance = instance.save()
|
|
|
|
|
|
|
|
See the `section on saving forms`_ for more details on using
|
|
|
|
``save(commit=False)``.
|
|
|
|
|
|
|
|
.. _section on saving forms: `The save() method`_
|
|
|
|
|
|
|
|
Overriding the default field types
|
|
|
|
----------------------------------
|
|
|
|
|
2008-01-28 03:56:35 +01:00
|
|
|
The default field types, as described in the `Field types`_ table above, are
|
2007-12-19 04:39:21 +01:00
|
|
|
sensible defaults. If you have a ``DateField`` in your model, chances are you'd
|
2007-12-02 20:29:54 +01:00
|
|
|
want that to be represented as a ``DateField`` in your form. But
|
|
|
|
``ModelForm`` gives you the flexibility of changing the form field type
|
|
|
|
for a given model field. You do this by declaratively specifying fields like
|
|
|
|
you would in a regular ``Form``. Declared fields will override the default
|
|
|
|
ones generated by using the ``model`` attribute.
|
|
|
|
|
|
|
|
For example, if you wanted to use ``MyDateFormField`` for the ``pub_date``
|
|
|
|
field, you could do the following::
|
|
|
|
|
|
|
|
>>> class ArticleForm(ModelForm):
|
|
|
|
... pub_date = MyDateFormField()
|
|
|
|
...
|
|
|
|
... class Meta:
|
|
|
|
... model = Article
|
2008-01-28 04:12:28 +01:00
|
|
|
|
|
|
|
If you want to override a field's default widget, then specify the ``widget``
|
|
|
|
parameter when declaring the form field::
|
|
|
|
|
|
|
|
>>> class ArticleForm(ModelForm):
|
|
|
|
... pub_date = DateField(widget=MyDateWidget())
|
|
|
|
...
|
|
|
|
... class Meta:
|
|
|
|
... model = Article
|
2008-02-14 13:56:49 +01:00
|
|
|
|
2008-09-01 21:08:08 +02:00
|
|
|
Overriding the clean() method
|
|
|
|
-----------------------------
|
|
|
|
|
2008-09-02 21:33:56 +02:00
|
|
|
You can override the ``clean()`` method on a model form to provide additional
|
|
|
|
validation in the same way you can on a normal form. However, by default the
|
2008-09-01 21:08:08 +02:00
|
|
|
``clean()`` method validates the uniqueness of fields that are marked as unique
|
2008-09-02 21:33:56 +02:00
|
|
|
or unique_together on the model. Therefore, if you would like to override
|
|
|
|
the ``clean()`` method and maintain the default validation, you must call the
|
2008-09-01 21:08:08 +02:00
|
|
|
parent class's ``clean()`` method.
|
|
|
|
|
2008-02-14 13:56:49 +01:00
|
|
|
Form inheritance
|
|
|
|
----------------
|
2008-02-16 06:15:09 +01:00
|
|
|
|
|
|
|
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::
|
2008-02-14 13:56:49 +01:00
|
|
|
|
|
|
|
>>> class EnhancedArticleForm(ArticleForm):
|
|
|
|
... def clean_pub_date(self):
|
|
|
|
... ...
|
|
|
|
|
2008-02-16 06:15:09 +01:00
|
|
|
This creates a form that behaves identically to ``ArticleForm``, except there's
|
|
|
|
some extra validation and cleaning for the ``pub_date`` field.
|
2008-02-14 13:56:49 +01:00
|
|
|
|
2008-02-14 18:38:05 +01:00
|
|
|
You can also subclass the parent's ``Meta`` inner class if you want to change
|
|
|
|
the ``Meta.fields`` or ``Meta.excludes`` lists::
|
|
|
|
|
|
|
|
>>> class RestrictedArticleForm(EnhancedArticleForm):
|
|
|
|
... class Meta(ArticleForm.Meta):
|
|
|
|
... exclude = ['body']
|
|
|
|
|
2008-02-16 06:15:09 +01:00
|
|
|
This adds the extra method from the ``EnhancedArticleForm`` and modifies
|
2008-02-14 18:38:05 +01:00
|
|
|
the original ``ArticleForm.Meta`` to remove one field.
|
|
|
|
|
2008-02-16 06:15:09 +01:00
|
|
|
There are a couple of things to note, however.
|
2008-02-14 13:56:49 +01:00
|
|
|
|
|
|
|
* Normal Python name resolution rules apply. If you have multiple base
|
|
|
|
classes that declare a ``Meta`` inner class, only the first one will be
|
2008-02-16 06:15:09 +01:00
|
|
|
used. This means the child's ``Meta``, if it exists, otherwise the
|
2008-02-14 13:56:49 +01:00
|
|
|
``Meta`` of the first parent, etc.
|
|
|
|
|
2008-02-16 06:15:09 +01:00
|
|
|
* For technical reasons, a subclass cannot inherit from both a ``ModelForm``
|
|
|
|
and a ``Form`` simultaneously.
|
2008-02-14 13:56:49 +01:00
|
|
|
|
2008-02-16 06:15:09 +01:00
|
|
|
Chances are these notes won't affect you unless you're trying to do something
|
|
|
|
tricky with subclassing.
|
2008-07-19 01:54:34 +02:00
|
|
|
|
2008-08-24 00:25:40 +02:00
|
|
|
.. _model-formsets:
|
|
|
|
|
2008-07-19 01:54:34 +02:00
|
|
|
Model Formsets
|
|
|
|
==============
|
|
|
|
|
2008-09-02 19:57:18 +02:00
|
|
|
Similar to :ref:`regular formsets <topics-forms-formsets>` there are a couple
|
|
|
|
enhanced formset classes that provide all the right things to work with your
|
|
|
|
models. Lets reuse the ``Author`` model from above::
|
2008-07-19 01:54:34 +02:00
|
|
|
|
2008-07-21 18:56:52 +02:00
|
|
|
>>> from django.forms.models import modelformset_factory
|
2008-07-19 01:54:34 +02:00
|
|
|
>>> AuthorFormSet = modelformset_factory(Author)
|
|
|
|
|
|
|
|
This will create a formset that is capable of working with the data associated
|
2008-09-02 19:57:18 +02:00
|
|
|
to the ``Author`` model. It works just like a regular formset just that we are
|
|
|
|
working with ``ModelForm`` instances instead of ``Form`` instances::
|
2008-07-19 01:54:34 +02:00
|
|
|
|
|
|
|
>>> 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" />
|
|
|
|
<tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" /></td></tr>
|
|
|
|
<tr><th><label for="id_form-0-title">Title:</label></th><td><select name="form-0-title" id="id_form-0-title">
|
|
|
|
<option value="" selected="selected">---------</option>
|
|
|
|
<option value="MR">Mr.</option>
|
|
|
|
<option value="MRS">Mrs.</option>
|
|
|
|
<option value="MS">Ms.</option>
|
|
|
|
</select></td></tr>
|
|
|
|
<tr><th><label for="id_form-0-birth_date">Birth date:</label></th><td><input type="text" name="form-0-birth_date" id="id_form-0-birth_date" /><input type="hidden" name="form-0-id" id="id_form-0-id" /></td></tr>
|
|
|
|
|
|
|
|
.. note::
|
2008-09-14 10:36:58 +02:00
|
|
|
``modelformset_factory`` uses ``formset_factory`` to generate formsets.
|
|
|
|
This means that a model formset is just an extension of a basic formset
|
|
|
|
that knows how to interact with a particular model.
|
2008-07-19 01:54:34 +02:00
|
|
|
|
|
|
|
Changing the queryset
|
|
|
|
---------------------
|
|
|
|
|
|
|
|
By default when you create a formset from a model the queryset will be all
|
|
|
|
objects in the model. This is best shown as ``Author.objects.all()``. This is
|
|
|
|
configurable::
|
|
|
|
|
|
|
|
>>> formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
|
|
|
|
|
|
|
|
Alternatively, you can use a subclassing based approach::
|
|
|
|
|
2008-07-21 18:56:52 +02:00
|
|
|
from django.forms.models import BaseModelFormSet
|
2008-07-19 01:54:34 +02:00
|
|
|
|
|
|
|
class BaseAuthorFormSet(BaseModelFormSet):
|
|
|
|
def get_queryset(self):
|
|
|
|
return super(BaseAuthorFormSet, self).get_queryset().filter(name__startswith='O')
|
|
|
|
|
|
|
|
Then your ``BaseAuthorFormSet`` would be passed into the factory function to
|
|
|
|
be used as a base::
|
|
|
|
|
|
|
|
>>> AuthorFormSet = modelformset_factory(Author, formset=BaseAuthorFormSet)
|
|
|
|
|
2008-09-02 19:57:18 +02:00
|
|
|
Controlling which fields are used with ``fields`` and ``exclude``
|
|
|
|
-----------------------------------------------------------------
|
|
|
|
|
|
|
|
By default a model formset will use all fields in the model that are not marked
|
|
|
|
with ``editable=False``. However, this can be overidden at the formset level::
|
|
|
|
|
|
|
|
>>> AuthorFormSet = modelformset_factory(Author, fields=('name', 'title'))
|
|
|
|
|
|
|
|
Using ``fields`` will restrict the formset to use just the given fields. Or if
|
|
|
|
you need to go the other way::
|
|
|
|
|
|
|
|
>>> AuthorFormSet = modelformset_factory(Author, exclude=('birth_date',))
|
|
|
|
|
|
|
|
Using ``exclude`` will prevent the given fields from being used in the formset.
|
|
|
|
|
|
|
|
.. _saving-objects-in-the-formset:
|
|
|
|
|
2008-07-19 01:54:34 +02:00
|
|
|
Saving objects in the formset
|
|
|
|
-----------------------------
|
|
|
|
|
|
|
|
Similar to a ``ModelForm`` you can save the data into the model. This is done
|
|
|
|
with the ``save()`` method on the formset::
|
|
|
|
|
|
|
|
# create a formset instance with POST data.
|
|
|
|
>>> formset = AuthorFormSet(request.POST)
|
|
|
|
|
|
|
|
# assuming all is valid, save the data
|
|
|
|
>>> instances = formset.save()
|
|
|
|
|
|
|
|
The ``save()`` method will return the instances that have been saved to the
|
|
|
|
database. If an instance did not change in the bound data it will not be
|
|
|
|
saved to the database and not found in ``instances`` in the above example.
|
|
|
|
|
|
|
|
You can optionally pass in ``commit=False`` to ``save()`` to only return the
|
|
|
|
model instances without any database interaction::
|
|
|
|
|
|
|
|
# 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 will also
|
|
|
|
need to make a call to ``formset.save_m2m()`` to ensure the many-to-many
|
|
|
|
relationships are saved properly.
|
|
|
|
|
2008-08-24 00:25:40 +02:00
|
|
|
.. _model-formsets-max-num:
|
|
|
|
|
2008-07-19 01:54:34 +02:00
|
|
|
Limiting the number of objects editable
|
|
|
|
---------------------------------------
|
|
|
|
|
|
|
|
Similar to regular formsets you can use the ``max_num`` parameter to
|
|
|
|
``modelformset_factory`` to limit the number of forms displayed. With
|
|
|
|
model formsets this will properly limit the query to only select the maximum
|
|
|
|
number of objects needed::
|
|
|
|
|
|
|
|
>>> Author.objects.order_by('name')
|
|
|
|
[<Author: Charles Baudelaire>, <Author: Paul Verlaine>, <Author: Walt Whitman>]
|
|
|
|
|
|
|
|
>>> AuthorFormSet = modelformset_factory(Author, max_num=2, extra=1)
|
|
|
|
>>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
|
|
|
|
>>> formset.initial
|
|
|
|
[{'id': 1, 'name': u'Charles Baudelaire'}, {'id': 3, 'name': u'Paul Verlaine'}]
|
|
|
|
|
|
|
|
If the value of ``max_num`` is less than the total objects returned it will
|
|
|
|
fill the rest with extra forms::
|
|
|
|
|
|
|
|
>>> AuthorFormSet = modelformset_factory(Author, max_num=4, extra=1)
|
|
|
|
>>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
|
|
|
|
>>> for form in formset.forms:
|
|
|
|
... print form.as_table()
|
|
|
|
<tr><th><label for="id_form-0-name">Name:</label></th><td><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" /></td></tr>
|
|
|
|
<tr><th><label for="id_form-1-name">Name:</label></th><td><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" /></td></tr>
|
|
|
|
<tr><th><label for="id_form-2-name">Name:</label></th><td><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" /></td></tr>
|
|
|
|
<tr><th><label for="id_form-3-name">Name:</label></th><td><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" /></td></tr>
|
|
|
|
|
2008-09-02 19:57:02 +02:00
|
|
|
Using a model formset in a view
|
|
|
|
-------------------------------
|
|
|
|
|
|
|
|
Model formsets are very similar to formsets. Lets say we want to present a
|
|
|
|
formset to a user to edit ``Author`` model instances::
|
|
|
|
|
|
|
|
def manage_authors(request):
|
|
|
|
AuthorFormSet = modelformset_factory(Author)
|
2008-09-12 17:52:39 +02:00
|
|
|
if request.method == 'POST':
|
2008-09-02 19:57:02 +02:00
|
|
|
formset = AuthorFormSet(request.POST, request.FILES)
|
|
|
|
if formset.is_valid():
|
|
|
|
formset.save()
|
|
|
|
# do something.
|
|
|
|
else:
|
|
|
|
formset = AuthorFormSet()
|
2008-12-09 01:31:17 +01:00
|
|
|
return render_to_response("manage_authors.html", {
|
2008-09-02 19:57:02 +02:00
|
|
|
"formset": formset,
|
|
|
|
})
|
|
|
|
|
|
|
|
As you can see the view is not drastically different than how to use a formset
|
|
|
|
in a view. The only difference is that we call ``formset.save()`` to save the
|
2008-09-02 19:57:18 +02:00
|
|
|
data into the database. This is described above in
|
|
|
|
:ref:`saving-objects-in-the-formset`.
|
2008-09-02 19:57:02 +02:00
|
|
|
|
2008-12-09 01:31:17 +01:00
|
|
|
Using a custom queryset
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
As stated earlier you can override the default queryset the model formset
|
|
|
|
uses::
|
|
|
|
|
|
|
|
def manage_authors(request):
|
|
|
|
AuthorFormSet = modelformset_factory(Author)
|
|
|
|
if request.method == "POST":
|
|
|
|
formset = AuthorFormSet(request.POST, request.FILES,
|
|
|
|
queryset=Author.objects.filter(name__startswith='O'))
|
|
|
|
if formset.is_valid():
|
|
|
|
formset.save()
|
|
|
|
# do something.
|
|
|
|
else:
|
|
|
|
formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
|
|
|
|
return render_to_response("manage_authors.html", {
|
|
|
|
"formset": formset,
|
|
|
|
})
|
2008-07-19 01:54:34 +02:00
|
|
|
|
2008-12-09 01:31:17 +01:00
|
|
|
What is critical to point out here is that you must pass the queryset in both
|
|
|
|
the ``POST`` and ``GET`` cases shown above.
|
|
|
|
|
|
|
|
Using the formset in the template
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
There are three ways you might want to render the formset in your template.
|
|
|
|
You can let the formset do most of the work::
|
|
|
|
|
|
|
|
<form method="POST" action="">
|
|
|
|
{{ formset }}
|
|
|
|
</form>
|
|
|
|
|
|
|
|
You can manually render the formset, but let the form deal with it self::
|
|
|
|
|
|
|
|
<form method="POST" action="">
|
|
|
|
{{ formset.management_form }}
|
|
|
|
{% for form in formset.forms %}
|
|
|
|
{{ form }}
|
|
|
|
{% endfor %}
|
|
|
|
</form>
|
|
|
|
|
|
|
|
When you manually render the forms yourself, be sure to render the management
|
|
|
|
form as shown above. Also see the :ref:`management form documentation <understanding-the-managementform>`.
|
|
|
|
|
|
|
|
Or you can just do it all yourself::
|
|
|
|
|
|
|
|
<form method="POST" action="">
|
|
|
|
{{ formset.management_form }}
|
|
|
|
{% for form in formset.formset %}
|
|
|
|
{% for fields in form %}
|
|
|
|
{{ field }}
|
|
|
|
{% endfor %}
|
|
|
|
{% endfor %}
|
|
|
|
</form>
|
|
|
|
|
|
|
|
It is critical to note that if you opt to do most of the work yourself and you
|
|
|
|
don't go with a field ``{% for %}`` loop of the form, as shown in the last
|
|
|
|
example, you need to render to the primary key field. For example if you were
|
|
|
|
to render just the ``name`` and ``age`` fields of a model::
|
|
|
|
|
|
|
|
<form method="POST" action="">
|
|
|
|
{{ formset.management_form }}
|
|
|
|
{% for form in formset.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 will ensure
|
|
|
|
the model formset, in the ``POST`` case, will work correctly. The above
|
|
|
|
example is assuming a primary key named ``id`` which is the name of the
|
|
|
|
implicit primary key Django creates for you when one isn't given. If you have
|
|
|
|
explicitly defined your own primary key field just make sure it gets rendered
|
|
|
|
(it is likely to be a visible field anyway).
|
|
|
|
|
|
|
|
Inline Formsets
|
|
|
|
===============
|
|
|
|
|
|
|
|
Inline formsets is a small abstraction layer on top of model formsets. It
|
|
|
|
simplifies the case of working with related objects via a foreign key. Suppose
|
|
|
|
you have these two models::
|
2008-09-02 19:57:18 +02:00
|
|
|
|
|
|
|
class Author(models.Model):
|
|
|
|
name = models.CharField(max_length=100)
|
|
|
|
|
|
|
|
class Book(models.Model):
|
|
|
|
author = models.ForeignKey(Author)
|
|
|
|
title = models.CharField(max_length=100)
|
|
|
|
|
|
|
|
If you want to create a formset that allows you to edit books belonging to
|
2008-12-09 01:31:17 +01:00
|
|
|
some author you might do::
|
2008-07-19 01:54:34 +02:00
|
|
|
|
2008-07-21 18:56:52 +02:00
|
|
|
>>> from django.forms.models import inlineformset_factory
|
2008-07-19 01:54:34 +02:00
|
|
|
>>> BookFormSet = inlineformset_factory(Author, Book)
|
|
|
|
>>> author = Author.objects.get(name=u'Orson Scott Card')
|
2008-09-01 21:08:08 +02:00
|
|
|
>>> formset = BookFormSet(instance=author)
|
2008-09-02 19:57:18 +02:00
|
|
|
|
2008-09-12 18:52:28 +02:00
|
|
|
.. note::
|
|
|
|
``inlineformset_factory`` uses ``modelformset_factory`` and marks
|
|
|
|
``can_delete=True``.
|
|
|
|
|
2008-09-06 02:09:17 +02:00
|
|
|
More than one foreign key to the same model
|
2008-12-09 01:31:17 +01:00
|
|
|
-------------------------------------------
|
2008-09-02 19:57:18 +02:00
|
|
|
|
|
|
|
If your model contains more than one foreign key to the same model you will
|
|
|
|
need to resolve the ambiguity manually using ``fk_name``. Given the following
|
|
|
|
model::
|
|
|
|
|
|
|
|
class Friendship(models.Model):
|
|
|
|
from_friend = models.ForeignKey(Friend)
|
|
|
|
to_friend = models.ForeignKey(Friend)
|
|
|
|
length_in_months = models.IntegerField()
|
|
|
|
|
|
|
|
To resolve this you can simply use ``fk_name`` to ``inlineformset_factory``::
|
|
|
|
|
|
|
|
>>> FrienshipFormSet = inlineformset_factory(Friend, Friendship, fk_name="from_friend")
|
2008-12-09 01:31:17 +01:00
|
|
|
|
|
|
|
Using an inline formset in a view
|
|
|
|
---------------------------------
|
|
|
|
|
|
|
|
You may want to provide a view that allows a user to edit the related objects
|
|
|
|
of some model. Here is how you might construct this view::
|
|
|
|
|
|
|
|
def manage_books(request, author_id):
|
|
|
|
author = Author.objects.get(pk=author_id)
|
|
|
|
BookInlineFormSet = inlineformset_factory(Author, Book)
|
|
|
|
if request.method == "POST":
|
|
|
|
formset = BookInlineFormSet(request.POST, request.FILES, instance=author)
|
|
|
|
if formset.is_valid():
|
|
|
|
formset.save()
|
|
|
|
# do something
|
|
|
|
else:
|
|
|
|
formset = BookInlineFormSet(instance=author)
|
|
|
|
return render_to_response("manage_books.html", {
|
|
|
|
"formset": formset,
|
|
|
|
})
|
|
|
|
|
|
|
|
Notice how we pass the instance in both the ``POST`` and ``GET`` cases. This
|
|
|
|
is required similiar to model formsets since the ``instance`` is simply used
|
|
|
|
to create the queryset for the model formset that lives underneath.
|