mirror of
https://github.com/django/django.git
synced 2024-12-23 17:46:27 +00:00
81b9b7fb55
git-svn-id: http://code.djangoproject.com/svn/django/trunk@6944 bcc190cf-cafb-0310-a4f2-bffc1f526a37
426 lines
17 KiB
Plaintext
426 lines
17 KiB
Plaintext
Generating forms for models
|
|
===========================
|
|
|
|
.. admonition:: Note
|
|
|
|
The APIs described in this document have been deprecated. If you're
|
|
developing new code, use `ModelForms`_ instead.
|
|
|
|
.. _ModelForms: ../modelforms/
|
|
|
|
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 few helper functions that let you create a
|
|
``Form`` class from a Django model.
|
|
|
|
``form_for_model()``
|
|
--------------------
|
|
|
|
The method ``django.newforms.form_for_model()`` creates a form based on the
|
|
definition of a specific model. Pass it the model class, and it will return a
|
|
``Form`` class that contains a form field for each model field.
|
|
|
|
For example::
|
|
|
|
>>> from django.newforms import form_for_model
|
|
|
|
# Create the form class.
|
|
>>> ArticleForm = form_for_model(Article)
|
|
|
|
# Create an empty form instance.
|
|
>>> f = ArticleForm()
|
|
|
|
It bears repeating that ``form_for_model()`` takes the model *class*, not a
|
|
model instance, and it returns a ``Form`` *class*, not a ``Form`` instance.
|
|
|
|
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``
|
|
``SlugField`` ``CharField``
|
|
``SmallIntegerField`` ``IntegerField``
|
|
``TextField`` ``CharField`` with ``widget=Textarea``
|
|
``TimeField`` ``TimeField``
|
|
``URLField`` ``URLField`` with ``verify_exists`` set
|
|
to the model field's ``verify_exists``
|
|
``USStateField`` ``CharField`` with
|
|
``widget=USStateSelect``
|
|
(``USStateSelect`` is from
|
|
``django.contrib.localflavor.us``)
|
|
``XMLField`` ``CharField`` with ``widget=Textarea``
|
|
=============================== ========================================
|
|
|
|
|
|
.. note::
|
|
The ``FloatField`` form field and ``DecimalField`` model and form fields
|
|
are new in the development version.
|
|
|
|
As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field
|
|
types are special cases:
|
|
|
|
* ``ForeignKey`` is represented by ``django.newforms.ModelChoiceField``,
|
|
which is a ``ChoiceField`` whose choices are a model ``QuerySet``.
|
|
|
|
* ``ManyToManyField`` is represented by
|
|
``django.newforms.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 field types" below.
|
|
|
|
A full example
|
|
~~~~~~~~~~~~~~
|
|
|
|
Consider this set of models::
|
|
|
|
from django.db import models
|
|
|
|
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)
|
|
|
|
With these models, a call to ``form_for_model(Author)`` would return a ``Form``
|
|
class equivalent to this::
|
|
|
|
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)
|
|
|
|
A call to ``form_for_model(Book)`` would return a ``Form`` class equivalent to
|
|
this::
|
|
|
|
class BookForm(forms.Form):
|
|
name = forms.CharField(max_length=100)
|
|
authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
|
|
|
|
The ``save()`` method
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Every form produced by ``form_for_model()`` also has a ``save()`` method. This
|
|
method creates and saves a database object from the data bound to the form. For
|
|
example::
|
|
|
|
# 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()
|
|
|
|
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
|
|
object before saving it. ``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 the form created by ``form_for_model``.
|
|
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.
|
|
>>> 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 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.
|
|
>>> f = AuthorForm(request.POST)
|
|
|
|
# Create and save the new author instance. There's no need to do anything else.
|
|
>>> new_author = f.save()
|
|
|
|
Using an alternate base class
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
If you want to add custom methods to the form generated by
|
|
``form_for_model()``, write a class that extends ``django.newforms.BaseForm``
|
|
and contains your custom methods. Then, use the ``form`` argument to
|
|
``form_for_model()`` to tell it to use your custom form as its base class.
|
|
For example::
|
|
|
|
# Create the new base class.
|
|
>>> class MyBase(BaseForm):
|
|
... def my_method(self):
|
|
... # Do whatever the method does
|
|
|
|
# Create the form class with a different base class.
|
|
>>> ArticleForm = form_for_model(Article, form=MyBase)
|
|
|
|
# Instantiate the form.
|
|
>>> f = ArticleForm()
|
|
|
|
# Use the base class method.
|
|
>>> f.my_method()
|
|
|
|
Using a subset of fields on the form
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
**New in Django development version**
|
|
|
|
In some cases, you may not want all the model fields to appear on the generated
|
|
form. There are two ways of telling ``form_for_model()`` to use only a subset
|
|
of the model fields:
|
|
|
|
1. Set ``editable=False`` on the model field. As a result, *any* form
|
|
created from the model via ``form_for_model()`` will not include that
|
|
field.
|
|
|
|
2. Use the ``fields`` argument to ``form_for_model()``. This argument, if
|
|
given, should be a list of field names to include in the form.
|
|
|
|
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`` like this::
|
|
|
|
PartialArticleForm = form_for_model(Author, fields=('name', 'title'))
|
|
|
|
.. note::
|
|
|
|
If you specify ``fields`` when creating a form with ``form_for_model()``,
|
|
then the fields that are *not* specified 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 ``form_for_model`` with missing fields will fail. To avoid
|
|
this failure, you must use ``save(commit=False)`` and manually set any
|
|
extra required fields::
|
|
|
|
instance = form.save(commit=False)
|
|
instance.required_field = 'new value'
|
|
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
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
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
|
|
``form_for_model()`` gives you the flexibility of changing the form field type
|
|
for a given model field. You do this by specifying a **formfield callback**.
|
|
|
|
A formfield callback is a function that, when provided with a model field,
|
|
returns a form field instance. When constructing a form, ``form_for_model()``
|
|
asks the formfield callback to provide form field types.
|
|
|
|
By default, ``form_for_model()`` calls the ``formfield()`` method on the model
|
|
field::
|
|
|
|
def default_callback(field, **kwargs):
|
|
return field.formfield(**kwargs)
|
|
|
|
The ``kwargs`` are any keyword arguments that might be passed to the form
|
|
field, such as ``required=True`` or ``label='Foo'``.
|
|
|
|
For example, if you wanted to use ``MyDateFormField`` for any ``DateField``
|
|
field on the model, you could define the callback::
|
|
|
|
>>> def my_callback(field, **kwargs):
|
|
... if isinstance(field, models.DateField):
|
|
... return MyDateFormField(**kwargs)
|
|
... else:
|
|
... return field.formfield(**kwargs)
|
|
|
|
>>> ArticleForm = form_for_model(Article, formfield_callback=my_callback)
|
|
|
|
Note that your callback needs to handle *all* possible model field types, not
|
|
just the ones that you want to behave differently to the default. That's why
|
|
this example has an ``else`` clause that implements the default behavior.
|
|
|
|
.. warning::
|
|
The field that is passed into the ``formfield_callback`` function in
|
|
``form_for_model()`` and ``form_for_instance`` is the field instance from
|
|
your model's class. You **must not** alter that object at all; treat it
|
|
as read-only!
|
|
|
|
If you make any alterations to that object, it will affect any future
|
|
users of the model class, because you will have changed the field object
|
|
used to construct the class. This is almost certainly what you don't want
|
|
to have happen.
|
|
|
|
Finding the model associated with a form
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The model class that was used to construct the form is available
|
|
using the ``_model`` property of the generated form::
|
|
|
|
>>> ArticleForm = form_for_model(Article)
|
|
>>> ArticleForm._model
|
|
<class 'myapp.models.Article'>
|
|
|
|
``form_for_instance()``
|
|
-----------------------
|
|
|
|
``form_for_instance()`` is like ``form_for_model()``, but it takes a model
|
|
instance instead of a model class::
|
|
|
|
# Create an Author.
|
|
>>> a = Author(name='Joe Smith', title='MR', birth_date=None)
|
|
>>> a.save()
|
|
|
|
# Create a form for this particular Author.
|
|
>>> AuthorForm = form_for_instance(a)
|
|
|
|
# Instantiate the form.
|
|
>>> f = AuthorForm()
|
|
|
|
When a form created by ``form_for_instance()`` is created, the initial data
|
|
values for the form fields are drawn from the instance. However, this data is
|
|
not bound to the form. You will need to bind data to the form before the form
|
|
can be saved.
|
|
|
|
Unlike ``form_for_model()``, a choice field in form created by
|
|
``form_for_instance()`` will not include the blank choice if the respective
|
|
model field has ``blank=False``. The initial choice is drawn from the instance.
|
|
|
|
When you call ``save()`` on a form created by ``form_for_instance()``,
|
|
the database instance will be updated. As in ``form_for_model()``, ``save()``
|
|
will raise ``ValueError`` if the data doesn't validate.
|
|
|
|
``form_for_instance()`` has ``form``, ``fields`` and ``formfield_callback``
|
|
arguments that behave the same way as they do for ``form_for_model()``.
|
|
|
|
Let's modify the earlier `contact form`_ view example a little bit. Suppose we
|
|
have a ``Message`` model that holds each contact submission. Something like::
|
|
|
|
class Message(models.Model):
|
|
subject = models.CharField(max_length=100)
|
|
message = models.TextField()
|
|
sender = models.EmailField()
|
|
cc_myself = models.BooleanField(required=False)
|
|
|
|
You could use this model to create a form (using ``form_for_model()``). You
|
|
could also use existing ``Message`` instances to create a form for editing
|
|
messages. The `simple example view`_ can be changed slightly to accept the ``id`` value
|
|
of an existing ``Message`` and present it for editing::
|
|
|
|
def contact_edit(request, msg_id):
|
|
# Create the form from the message id.
|
|
message = get_object_or_404(Message, id=msg_id)
|
|
ContactForm = form_for_instance(message)
|
|
|
|
if request.method == 'POST':
|
|
form = ContactForm(request.POST)
|
|
if form.is_valid():
|
|
form.save()
|
|
return HttpResponseRedirect('/url/on_success/')
|
|
else:
|
|
form = ContactForm()
|
|
return render_to_response('contact.html', {'form': form})
|
|
|
|
Aside from how we create the ``ContactForm`` class here, the main point to
|
|
note is that the form display in the ``GET`` branch of the function
|
|
will use the values from the ``message`` instance as initial values for the
|
|
form field.
|
|
|
|
.. _contact form: ../newforms/#simple-view-example
|
|
.. _`simple example view`: ../newforms/#simple-view-example
|
|
|
|
When should you use ``form_for_model()`` and ``form_for_instance()``?
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The ``form_for_model()`` and ``form_for_instance()`` functions are meant to be
|
|
shortcuts for the common case. If you want to create a form whose fields map to
|
|
more than one model, or a form that contains fields that *aren't* on a model,
|
|
you shouldn't use these shortcuts. Creating a ``Form`` class the "long" way
|
|
isn't that difficult, after all.
|