Previous Page Next Page

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())

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())

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())

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.


Try It Yourself: Create and Render a Form for a Model

In this section, you will create a person_form() view that displays a Person object as a form. Follow these steps to add the person_form() that creates a form from a Person object, create an HTML template to display the form, and update the URLconf file to enable the view:

1.
Open the iFriends/People/views.py file in an editor.

2.
Add the following code to the file, as shown in Listing 10.3, to define a person_form() function that accepts the argument pID and retrieves a Person object from the database:

def person_form(request, pID='0'):
    p = get_object_or_404(Person, pk=pID)

3.
Add the following code to the function created in step 2 to create a PersonForm class from the Person object instance, and then create an instance of the PersonForm:

PersonForm = forms.form_for_instance(p)
pForm = PersonForm()

4.
Add the following line of code to the person_form() function, as shown in Listing 10.3, to render the form to a template called person_form.html:

return render_to_response('People/person_form.html', {'pForm':pForm})

5.
Save the iFriends/People/views.py file.

6.
Create and open a file named iFriends/templates/People/person_form.html in an editor.

7.
Add the template code shown in Listing 10.4 to extend the base template and render the pForm variable as a table.

8.
Save the iFriends/templates/Person/person_form.html file.

9.
Open the iFriends/People/urls.py file in an editor.

10.
Add the following line to the URL patterns to provide the URL link to the person_form() view function:

(r'^Form/(?P<pID>\d+)/$', 'person_form'),

11.
Save the iFriends/People/urls.py file.

12.
Access the following URL in a web browser to bring up the person form view, as shown in Figure 10.5, and verify that the form renders correctly:

http://127.0.0.1:8000/People/Form/1/

Figure 10.5. Person form rendered as an HTML table in the person_form.html template.


Listing 10.3. Full Contents of iFriends/People/views.py

from django.http import HttpResponse
from django.shortcuts import render_to_response, get_object_or_404
from iFriends.People.models import Person, Blog
from iFriends.Quotes.models import Quote
from datetime import datetime
from django import newforms as forms

def index(request):
    pList = Person.objects.all()
    return render_to_response('people/person_index.html', {'pList': pList})

def details(request, pID='0', opts=()):
    rDict = {}
    p = get_object_or_404(Person, pk=pID)
    rDict['p'] = p
    quotes = Quote.objects.all()
    rDict['quotes'] = quotes
    return render_to_response('people/person_details.html', rDict)

def person_form(request, pID='0'):
    p = get_object_or_404(Person, pk=pID)
    PersonForm = forms.form_for_instance(p)
    pForm = PersonForm()
    return render_to_response('People/person_form.html', {'pForm':pForm})

Listing 10.4. Full Contents of iFriends/templates/People/person_form.html

{% extends "iFriends_base.html" %}

{% block title %}Person Form{% endblock %}
{% block content %}
<table>
{{ pForm }}
</table>
{% endblock %}


Previous Page Next Page