From 6500f3fefacc65f8e3167f80a498ea296b3e6ba2 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Sat, 12 May 2007 17:02:44 +0000 Subject: [PATCH] Edited changes to docs/newforms.txt from [5202] git-svn-id: http://code.djangoproject.com/svn/django/trunk@5212 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- docs/newforms.txt | 333 +++++++++++++++++++++++++++++++++------------- 1 file changed, 238 insertions(+), 95 deletions(-) diff --git a/docs/newforms.txt b/docs/newforms.txt index 5d19eeac3a..a7c250be01 100644 --- a/docs/newforms.txt +++ b/docs/newforms.txt @@ -873,158 +873,304 @@ mentioned above (``required``, ``label``, ``initial``, ``widget``, 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 - >>> 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 + # 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 ``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 + + ``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 @@ what's possible. 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 -=======