Chapter 10. Adding Forms to Views

<feature><title>What You’ll Learn in This Hour</title> <objective>

How to create Form instances

</objective>
<objective>

How to render Form objects as HTML code

</objective>
<objective>

How to render forms for models and objects

</objective>
<objective>

How to create custom forms by customizing Widgets and using custom templates

</objective>
</feature>

Forms are a basic element of any website. HTML forms are used to collect input from users. This input can be used to change data in the database, configure settings, send emails, and perform various other tasks.

Django provides a useful library to help you create and handle forms. The Django forms library is intended to handle HTML form display, data processing, and redisplay. In this hour, you will learn how to create forms and display them in your HTML views. We won’t actually gather any input from the forms in this hour; that topic is covered in the next hour.

Before starting this hour, you need to understand a few terms:

  • Model: We covered models earlier. You should remember that a model is an object-definition with several fields defined that define attributes of the object.

  • Form: In this hour, form refers to a Django Form class that is used to render HTML forms.

  • Field: Both models and forms have Field objects. The Field objects for models and forms are similar and are somewhat related, but they are not the same. Appendix B, “Django Form Field Objects,” contains a table that maps Model Fields to Form Fields.

  • Widget: A Widget is an object that renders to an HTML form element. Each Form Field has an associated Widget object that is used when rendering the Form as HTML. For example, a CharField Widget renders to an HTML text input element. Appendix B lists the Widget objects.

Watch Out!

Currently, the two form libraries are forms and newforms. The forms library is old, so it isn’t covered in this book. The Django project suggests that you import the newforms library as forms to maintain backward compatibility. Perhaps the Django developers intend to remove the old forms library and replace it with newforms. In this book, however, I always import the newforms library using the following import statement:

from django import newforms as forms

When I refer to the forms library, I am really referring to the newforms library.

Creating Form Instances

You can define forms in Django by creating a class that inherits the Form class and then defining Field objects as members of the form. For example, to create an address book form that includes name, address, and email fields, you would use the following class definition:

from django import newforms as forms
class AddressForm(forms.Form):
    name = forms.CharField()
    address = forms.CharField()
    email = forms.EmailField()

After the form has been created, you can create instances of the form by calling this constructor:

adr = AddressForm()

The following sections describe the different fields you can use when defining forms, how to create bound and unbound instances of the forms, and how to override built-in form methods.

Form Fields

You can add several different types of fields to forms. The advantage of different types of fields is that the form can more closely match the data types that will be put into it and validated.

Several Field objects are available in the forms package. The following is a list of the Field objects and their uses. For more information about each Field object, see Appendix B.

  • The BooleanField object is used to add true/false values. It renders a check box.

  • The CharField object is used for most textual input. It renders a text box.

  • The ChoiceField object is used to select an item from a list. It renders a select box.

  • The DateField object is used to specify a date. It renders a text box.

  • The DateTimeField object is used to specify a date/time. It renders a text box.

  • The DecimalField object is used to specify numeric data in the form of a decimal value. It renders a text box.

  • The EmailField object is used to specify an email address. It renders a text box.

  • The FileField object is used to specify a file. It renders a file upload.

  • The ImageField object is used to specify an image file. It renders a file upload.

  • The IntegerField object is used to specify numeric data in the form of an integer value. It renders a text box.

  • The IPAddressField object is used to specify an IPv4 address. It renders a text box.

  • The MultipleChoiceField object is used to select multiple items from a list. It renders a multiple-select box.

  • The NullBooleanField object is used to select a true/false/none value. It renders a null Boolean select.

  • The RegexField object is used to specify that you want a specific regular expression as the input. It renders a text box.

  • The TimeField object is used to specify a time. It renders a text box.

  • The URLField object is used to specify a valid URL. It renders a text box.

Each Field object has the following core field arguments available when you define the form:

  • The required argument can be set to True or False; it defaults to True. If required is set to False, no value is required when creating or validating the form.

  • The label argument allows you to specify a textual label that is displayed when the form is rendered. If label is not specified, the name of the field is used.

  • The initial argument allows you to specify an initial value for the field. initial is used only with unbound forms.

  • The widget argument allows you to specify a Widget object to use when rendering the field. The Widget object determines what HTML element is used in the form when it is rendered. For more details about the types of Widget objects you can assign to fields, see Appendix B.

  • The help_text argument allows you to specify a string that is displayed next to the field when the field is rendered.

The following example shows a simple Field definition that uses the core field arguments:

desc = forms.CharField(required=False, label='Description',
          widget=forms.Textarea(), help_text='Your description here.')

Bound and Unbound Forms

You can create two different types of form instances, depending on what you need from the form. You can create forms that are either bound or unbound to data. A bound form is a form that contains data bound to each element in the form. An unbound form is a blank form that contains no data values for the elements in the form.

A form that is unbound to data cannot do validation, but it can still render the form so that it can be displayed as HTML. To create an unbounded instance of a form, you simply need to call the Form constructor. The following example creates an unbound form:

adr = AddressForm()

A form that is bound to data can validate that data as well as render it to be displayed as HTML. To create a bound instance of a form, you need a dictionary. The dictionary’s keys need to match the names of the fields you specified when you defined the form. The values need to be valid for the Field object that the key specifies. The following example shows how to create a form that is bound to a dataset:

from django import newforms as forms
class AddressForm(forms.Form):
    name = forms.CharField()
    address = forms.CharField()
    email = forms.EmailField()
. . .
dset = {'name': 'Surfs Up',
        'address': 'Somewhere Wet',
        'email': '[email protected]'}
adr = AddressForm(dset)

When the AddressForm instance is created, it is bound to the data in dset.

Watch Out!

Bound forms should be considered immutable. You cannot change the data after the form has been created. To change the data, you need to create another instance of the form.

By the Way

To determine whether a form instance is bound, you can access the is_bound attribute of the Form object. For the preceding example, the following line of code would evaluate to True:

adr.is_bound

Rendering Forms as HTML

An instance of a Form object can be rendered as HTML in a couple of ways. The first way is to render the form inside Python code—for example, inside a view function when building the text for the HttpResponse. The second way is to pass the form object as a variable to an HTML template file and then render the form inside the template itself.

Django provide three different versions of form rendering. The following sections discuss rendering forms as tables, lists, and paragraphs. The table version seems to be the most popular. Which one you use depends on how you want the form to be displayed.

Rendering Forms as a Table

Django provides the as_table() function to render forms as an HTML table. This method is also the default method if you simply use the print function to print the form.

When forms are rendered as an HTML table, each Field in the form is rendered as a two-column row. The first column displays the label in a <th> tag. The second column uses the HTML equivalent of the Widget object assigned to the Field to display the value in a <td> tag. For example, a CharField that is labeled Name and has a value of Tim renders to the following HTML:

<tr><th><label for"id_name"Name:</label><th>
<td><input type="text" name="name" value="Tim" /></td></tr>

By the Way

There are no <table> or <form> tags around the rendered table. This gives you much more flexibility in building the view.

The following line of code shows how to render a Form object as an HTML table in Python code:

html += myForm.as_table()

The following line of code shows how to render a Form object as an HTML table in an HTML template:

{{ myForm.as_table }}

Rendering Forms as a List

Django provides the as_ul() function to render forms as an HTML list. When forms are rendered as an HTML list, each Field in the form is rendered as a list item with a <label> and <input> tag. The <label> tag displays the label of the Field. The <input> tag displays the HTML equivalent of the Widget object assigned to the Field. For example, a CharField that is labeled Name and has a value of Tim renders to the following HTML:

<li><label for"id_name"Name:</label>
<input type="text" name="name" value="Tim" /></li>

By the Way

There are no <form> tags around the rendered list. This gives you much more flexibility in building the view.

The following line of code shows how to render a Form object as an HTML list in Python code:

html += myForm.as_ul()

The following line of code shows how to render a Form object as an HTML list in an HTML template:

{{ myForm.as_ul }}

Rendering Forms as Paragraphs

Django provides the as_p() function to render forms as HTML paragraphs. When forms are rendered as HTML paragraphs, each Field in the form is rendered inside <p> tags with <label> and <input> tags. The <label> tag displays the label of the Field. The <input> tag displays the HTML equivalent of the Widget object assigned to the Field. For example, a CharField that is labeled Name and has a value of Tim renders to the following HTML:

<p><label for"id_name"Name:</label>
<input type="text" name="name" value="Tim" /></p>

By the Way

There are no <form> tags around the rendered paragraph. This gives you much more flexibility in building the view.

The following line of code shows how to render a Form object as an HTML paragraph in Python code:

html += myForm.as_p()

The following line of code shows how to render a Form object as an HTML paragraph in an HTML template:

{{ myForm.as_p }}

Rendering Forms from Models

In the previous sections, you learned how to define new Form objects and render them as HTML. Django also allows you to create Form objects from a model or an instance of a model.

Creating forms from models is easy and limits coding errors. However, you do not have as much control over forms created from models as forms you create yourself.

The following sections describe the process of creating a form from a model class using the form_for_model() helper function and creating a form from a model instance using the form_for_instance() helper function.

Creating a Form from a Model

The form_for_model() function accepts a model class and creates a Form class with a Field object that corresponds to each Field object in the model. You can then use the Form class to create Form instances that can be rendered as HTML. For a mapping of Form Fields to Model Fields, see Appendix B.

For example, let’s look at creating a Form object from this Blog model:

class Blog(models.Model):
    title = models.CharField('Title', max_length=200)
    text = models.TextField('Text', max_length=2048)
    date = models.DateTimeField('Last Modified')

The following code snippet creates a Form class from the Blog model, creates a Form instance from the Form class, and renders it as HTML paragraphs, as shown in Figure 10.2:

from django.http import HttpResponse
from iFriends.People.models import Blog
from django import newforms as forms
. . .
BlogForm = forms.form_for_model(Blog)
bf = BlogForm()
return HttpResponse(bf.as_p())
Blog form generated from form_for_model() and rendered as HTML paragraphs.

Figure 10.2. Blog form generated from form_for_model() and rendered as HTML paragraphs.

Did you Know?

If you set the editable=False option when creating a Field in a model, that Field is not added to the Form class created by form_for_model() or form_for_instance().

Creating a Form from an Object

You can use the form_for_instance() helper function to create a Form class from an object that is a model instance. The form_for_instance() function works basically the same way as the form_for_model() function. For each Field object in the model, a corresponding Field is created in the Form class.

The big difference is that the data values from the model instance are assigned as initial values of the form. When the Form is rendered as HTML, those values are placed as initial values in the form.

Another advantage of using the form_for_instance() function is that you don’t necessarily need to know what model is being rendered. This can be helpful if you want to write generic views that will render forms from different types of objects.

For an example, let’s use the Blog class defined in the preceding section. The following code snippet uses form_for_instance() to create a Form class from the Blog object instance, creates a Form instance from the Form class, and renders it as HTML paragraphs, as shown in Figure 10.3:

from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from iFriends.People.models import Blog
from django import newforms as forms
. . .
blog = get_object_or_404(Blog, pk=1)
BlogForm = forms.form_for_instance(blog)
bf = BlogForm()
return HttpResponse(bf.as_p())
Blog form with initial values filled in, generated from form_for_instance(), and rendered as HTML paragraphs.

Figure 10.3. Blog form with initial values filled in, generated from form_for_instance(), and rendered as HTML paragraphs.

Notice that the form’s values are already filled in with the values in the Blog instance.

Creating Partial Forms from Models

The form_for_model() and form_for_instance() functions accept a fields argument that allows you to specify which Field objects are added to the Form class. The fields argument is set to a list of Field names that exist in the model. Only the fields that are listed in the fields argument are added to the Form class.

The fields argument gives you more flexibility when creating forms for models. For example, consider the Blog class from the previous sections. The Last Modified field isn’t something that the user needs to modify. The following code snippet uses the fields argument in form_for_instance() to create a Form class that is a subset of the Blog object instance. The Form class includes only the title and text fields that are listed in the fields argument, as shown in Figure 10.4:

from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from iFriends.People.models import Blog
from django import newforms as forms
. . .
blog = get_object_or_404(Blog, pk=1)
BlogForm = forms.form_for_instance(blog, fields=('title', 'text')
bf = BlogForm()
return HttpResponse(bf.as_p())
Blog form that includes only the title and text fields rendered as HTML paragraphs.

Figure 10.4. Blog form that includes only the title and text fields rendered as HTML paragraphs.

Notice that the Last Modified field is not present in the form because it is not listed in the fields argument.

Watch Out!

Fields that are omitted from the fields argument must not be required for validation. They need to be allowed to have a None value by setting Blank=True, contain a default value, or be filled in automatically.

Customizing Forms

The HTML look and feel of the forms that Django renders seems a bit limited and plain. However, you can add code to both the Python view function and the HTML template to customize the form’s look and feel. The following sections discuss changing the look and feel of the HTML forms.

Customizing Widgets

One of the biggest changes you can make to alter the look and feel of a Form Field object is to change the Widget object. All Field objects have an associated Widget object that is used to generate the HTML code for the Field. Appendix B has more information on Form Fields and Widgets.

Django allows you to specify attributes for the Widget as well as specify a totally different Widget to use for the form. Changing the Widget results in changing the HTML code that is generated when the form is rendered as HTML.

For example, consider the following Form code, which renders a form similar to the one shown in Figure 10.6:

class MForm(forms.Form):
    name = forms.CharField(max_length=50)
    location = forms.CharField(max_length=80)
    size = forms.CharField(max_lenght=20))
    desc = forms.CharField(max_length=200)
Simple form rendered as an HTML table.

Figure 10.6. Simple form rendered as an HTML table.

All the HTML elements are text inputs and are the same size even though the Fields are for different types of data. The following definition for the form sets the size attribute of the length field and changes the size field to a RadioSelect and the desc field to a Textarea, as shown in Figure 10.7:

sList = [('S', 'Hill'),('M','Peak'), ('L', 'Climber')]
class MForm(forms.Form):
    name = forms.CharField(max_length=50)
    location = forms.CharField(widget=
               forms.TextInput(attrs={'size':'40'}))
   size = forms.CharField(widget=
               forms.RadioSelect(choices=sList))
   desc = forms.CharField(widget=forms.Textarea(
               attrs={'rows':'4','cols':'40'}))
Form class with customized Widgets rendered as an HTML table.

Figure 10.7. Form class with customized Widgets rendered as an HTML table.

The form in Figure 10.7 would be much more useful, and it doesn’t take that much extra code.

Watch Out!

The only thing you really need to watch out for when customizing forms is to make sure that they still conform to the data that you work with.

Customizing Forms in Templates

Another way to customize your forms is using HTML templates. When you pass forms into a template, you can access the fields directly using the . (dot) syntax. This allows you to access not only the value of the field, but also the field attributes, such as label_tag and help_text.

The following code snippet from an HTML template shows how you can access an instance of the MForm from the preceding section and use your own HTML code to control how it is displayed, as shown in Figure 10.8:

<table>
<tr>
    <th>{{ MForm.name.label_tag }}</th>
    <td>{{ MForm.name }}</td>
    <th>{{ MForm.location.label_tag }}:</th>
    <td>{{ MForm.location }}</td>
</tr>
<tr>
    <th>{{ MForm.desc.label_tag }}:</th>
    <td colspan="3">{{ MForm.desc }}</td>
</tr>
</table>
<h3>{{ MForm.size.label_tag }}</h3>
{{ MForm.size }}
Form class with customized Widgets rendered using - custom template code.

Figure 10.8. Form class with customized Widgets rendered using - custom template code.

By the Way

You can also access the Form as a list in the template and use it in a for loop. This makes it easy to apply the same HTML code to several fields. For example:

{% for field in MForm %}
<h2>{{ field.label_tag }}</h2>
{{ field }}
{% endfor %}

Summary

This hour discussed how to create Form objects in Django by defining each field. It also discussed how to quickly create Form objects from models using the form_for_model() and form_for instance() functions. This hour discussed rendering forms to HTML as well.

In the final section of this hour, you learned how to customize the look and feel of the rendered form by customizing the Widget and using custom template code.

Q&A

Q.

Is there a way to find out what model is associated with a Form instance?

A.

Yes. The model can be accessed using the _model of the Form instance. Here’s an example:

objClass = ContactForm._model

Q.

Can I create my own Widget?

A.

Yes. The following code defines a custom TextInput Widget that can be used in Forms:

class myWidget(forms.TextInput):
    def __init__(self, *args, **kwargs):
    kwargs.setdefault('attrs', {}).update({'size': '60'})
    super(myWidget, self).__init __(*args, **kwargs)

Workshop

The workshop consists of a set of questions and answers designed to solidify your understanding of the material covered in this hour. Try answering the questions before looking at the answers.

Quiz

1.

What format is a form rendered in if you do not use the as_p, as_ul, or as_table functions?

2.

How do you set the initial values for a form?

3.

How to you create a form directly from a model?

4.

How can you access the value of form elements from within a template?

Quiz Answers

1.

The form is rendered as a table.

2.

There are three ways. You can create the form from an instance of an object. You can set the initial attribute of the Fields in the form when you define it. You can pass a dictionary to the Form constructor when you create an instance of the form.

3.

Call the django.newforms.form_for_model() function and pass it the model class.

4.

You can use the dot syntax in a template to access form elements; for example, form1.name.

Exercises

1.

Create a view function in the iFriends/People/views.py file that creates a Form instance for a Blog object.

2.

Create an HTML template in the iFriends/templates/People directory that displays the Blog form you created in Exercise 1. Add a render_to_response() call to the view function to render the view to the new template.

3.

Add an entry to the URLconf file to enable the Blog view to be accessed from a web browser.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.201.71