Author: adrian
Date: 2007-05-12 12:02:44 -0500 (Sat, 12 May 2007)
New Revision: 5212
Modified:
django/trunk/docs/newforms.txt
Log:
Edited changes to docs/newforms.txt from [5202]
Modified: django/trunk/docs/newforms.txt
===================================================================
--- django/trunk/docs/newforms.txt 2007-05-12 16:53:27 UTC (rev 5211)
+++ django/trunk/docs/newforms.txt 2007-05-12 17:02:44 UTC (rev 5212)
@@ -873,158 +873,304 @@
Generating forms for models
===========================
-Although you can build customized forms by specifying the fields manually,
-in many cases you won't need to. Django provides helper methods to simplify the
-common cases of form creation.
+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()``
--------------------
-This method creates a form based upon the definition for a specific model.
-``form_for_model()`` examines the model definition, and creates a new form
-class that contains a form field for each model field that is defined.
+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.
-The type of fields produced on the generated form is determined by the type
-of the model fields. For example, a ``CharField`` on a model will be
-represented with a ``CharField`` on the form. Each ``ManyToManyField``
-on the model will be represented with a ``MultipleChoiceField`` on the
-form. Each ``ForeignKey`` will be represented with a ``ChoiceField``.
-A ``ChoiceField`` is also used for any model field that has a ``choices``
-attribute specified.
+For example::
-``form_for_model()`` returns a generated class. This class must then be
-instantiated::
+ >>> from django.newforms import form_for_model
- # Create the form class
+ # Create the form class.
>>> ArticleForm = form_for_model(Article)
-
- # Create an empty form instance
+
+ # Create an empty form instance.
>>> f = ArticleForm()
-
-The form produced by ``form_for_model`` also has a ``save()`` method. Once the
-form contains valid data, the ``save()`` method can be used to create a model
-instance with the attribute values described on the form::
- # Create a form instance populated with POST data
+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 ``maxlength``
+ ``CommaSeparatedIntegerField`` ``CharField``
+ ``DateField`` ``DateField``
+ ``DateTimeField`` ``DateTimeField``
+ ``EmailField`` ``EmailField``
+ ``FileField`` ``CharField``
+ ``FilePathField`` ``CharField``
+ ``FloatField`` ``CharField``
+ ``ForeignKey`` ``ModelChoiceField`` (see below)
+ ``ImageField`` ``CharField``
+ ``IntegerField`` ``IntegerField``
+ ``IPAddressField`` ``CharField``
+ ``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``
+ =============================== ========================================
+
+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``.
+
+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(maxlength=100)
+ title = models.CharField(maxlength=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(maxlength=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 the new instance
+ # 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``.
+
Using an alternate base class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If you want to add other methods to the generated form, you can put those
-methods onto a base class, and instruct ``form_for_model()`` to use that
-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::
-By default, every form produced by ``form_for_model()`` extends
-``django.newforms.forms.BaseForm``. However, if you provide a ``forms``
-argument to ``form_for_model()``, Django will use that class as the base
-for the form it generates::
-
- # Create the new base class:
+ # Create the new base class.
>>> class MyBase(BaseForm):
- ... def fiddle(self):
+ ... def my_method(self):
... # Do whatever the method does
- # Create the form class with a different base class
+ # Create the form class with a different base class.
>>> ArticleForm = form_for_model(Article, form=MyBase)
- # Instantiate the form
+ # Instantiate the form.
>>> f = ArticleForm()
-
- # Use the base class method
- >>> f.fiddle()
-Putting a subset of fields on the form
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ # 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 form.
-One option is to set ``editable=False`` on the model field.
``form_for_model()``
-will not include any non-editable fields on a generated form instance.
+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:
-However, if you just want to exclude a field from one specific form, you
-can use the ``fields`` argument. If you provide a fields argument to
-``form_for_model()``, only the fields named will be included on the form.
-For example, if you only want the 'title' and 'pub_date' attributes to be
-included on the Article form, you would call::
+ 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.
- >>> PartialArticleForm = form_for_model(Article, fields=('title',
'pub_date'))
+ 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()``
- make sure that the fields that are *not* specified can provide default
- values, or are allowed to have a value of ``None``. If a field isn't
- specified on a form, the object created from the form can't provide
- a value for that attribute, which will prevent the new instance from
+
+ If you specify ``fields`` when creating a form with ``form_for_model()``,
+ make sure that the fields that are *not* specified can provide default
+ values, or are allowed to have a value of ``None``. If a field isn't
+ specified on a form, the object created from the form can't provide
+ a value for that attribute, which will prevent the new instance from
being saved.
Overriding the default field types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Although the form field types generated by ``form_for_model()`` are suitable
-for most general purposes, you may have need to override the default field
-types on a specific form. In order to do this, ``form_for_model()`` provides
-access to the *formfield callback*.
+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*.
-The formfield callback is a function that, when provided with a model field,
+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. The default
-implementation asks the model field for an appropriate field type; however,
-any other strategy may be employed. If you need to use an alternate strategy,
-you can define your own callback, and provide it to ``form_for_model()`` using
-the ``formfield_callback`` argument.
+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``
-fields on the model, you could define the callback::
+field on the model, you could define the callback::
- >>> def my_fields(field, **kwargs):
+ >>> def my_callback(field, **kwargs):
... if isinstance(field, models.DateField):
... return MyDateFormField(**kwargs)
- ... else:
+ ... else:
... return field.formfield(**kwargs)
-
- >>> ArticleForm = form_for_model(formfield_callback=my_fields)
-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.
+ >>> ArticleForm = form_for_model(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.
+
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.
-
+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 very similar to ``form_for_model()``. However,
-rather than using a model class to generate a form, it uses an instance of a
-model::
+``form_for_instance()`` is like ``form_for_model()``, but it takes a model
+instance instead of a model class::
- # Create an article
- >>> art = Article(... some data ...)
- >>> art.save()
-
- # Create a form
- >>> ArticleForm = form_for_instance(art)
-
- # Instantiate the form
- >>> f = ArticleForm()
+ # 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
+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.
-When you call ``save()`` on a form created by ``form_for_instance()``,
-the database instance will be updated.
+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``
+``form_for_instance()`` has ``form``, ``fields`` and ``formfield_callback``
arguments that behave the same way as they do for ``form_for_model()``.
+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.
+
More coming soon
================
@@ -1035,6 +1181,3 @@
If you're really itching to learn and use this library, please be patient.
We're working hard on finishing both the code and documentation.
-
-Widgets
-=======
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en
-~----------~----~----~----~------~----~------~--~---