Project Environment 3 Django Forms
Interacting with our applications
Saw in an earlier class we use forms to allow users to interact with our application and pass data.
We saw a simple example of using an HTML form in a template to allow the user to submit a search query.
To allow users to Create and Update data maintained by our applications, Django provides Django forms.
Django forms provide a simple service: For data input by the user, they provide a place to hold the data temporarily and to validate it.
If all you need is standard validation, Django’s generic views can generate forms automatically given a model class.
COMP3297: Software Engineering 2
As an example, let’s take the Course Management case from earlier.
Remember: Courses have a unique course code, and a name. Some small changes in functionality just for this demo:
The course list will show only course codes, which will link to the details (here, only course name) of their corresponding courses.
COMP3297: Software Engineering 3
Some generic views expect us put a bit of expected “infrastructure” in place first. get_absolute_url()
Generally, hard-coding paths in our code is bad. Every time there is a change, we need to find every occurrence in the code.
We define get_absolute_url() functions that can give us a URL we need from a single authoritative point. And that Django will use, for example, when it wants the URL for an instance.
A common need is for the URL of the “official page” that represents an instance. Usually, this is some form of detail page.
Since the mapping from URL to view of an instance already exists in our URLconfs, we don’t even need to hard code URL details in get_absolute_url(). We can reverse the mapping to obtain the URL.
We’ll see soon this is useful for redirecting the user to the detail of a instance after it has been created or updated successfully.
COMP3297: Software Engineering 4
Reversing a URL pattern
In the Course model:
Also switched to use a UUID field for ID, as an example of this type as primary key
reverse() uses the name we gave to the URL, the number of arguments, and the names of keyword arguments to find the match
COMP3297: Software Engineering
5
Example of use
COMP3297: Software Engineering 6
In the course_list template:
example of overriding content of the base template
Also more useful naming.
This example shows the new context object name explicitly.
That form of the name is such a common choice that Django provides it implicitly. Thus the statement could be omitted and we could still access course_list in our template.
Django’s generic editing views
CRUD operations are a common need. Django provides generic views that work with forms to make CUD very straightforward:
CreateView:
Displays a form for creating an object, and saves the object
UpdateView:
Displays a form for updating an existing object and saves it
DeleteView:
Displays a confirmation page and deletes the object
Those views are all model-based. There is an additional editing view that is not model-based
FormView:
Displays a form and performs corresponding action
COMP3297: Software Engineering 7
Create, with CreateView
In views.py:
Form for course creation (a ModelForm) generated automatically
If success_url is not given a value, Will call get_absolute_url() of new instance for redirect if success_url is not given a value.
Will use a template_name of
8
Remember, our get_absolute_url() reverses this to obtain a URL
In courses/urls.py:
In the course_form.html template:
COMP3297: Software Engineering
In action
Obtained via the model’s COMP3297: Software Engineering get_absolute_url() function9
By template inheritance and overriding
Automatically redirects here on success.
Too much magic?
What is happening with the Form?
Easiest way to understand Django Forms is by their basic purpose and the states they can be in.
The purpose of a Form is to:
create HTML forms for data
hold data temporarily
validate and process the data
pass the result on for further action (such as saving in the database)
Forms contain fields, declared in a similar way to Models. But the fields are different from those of Models.
Form fields are associated with a widget – an HTML element, effectively, so they can be represented to users in the browser.
They don’t know how to represent data in a database – that is the job of Model
fields.
COMP3297: Software Engineering 10
What is happening with the Form?
Ultimately, Django Forms do something with the data. By convention we usually implement a save() method for that purpose (although, it could be send(), etc. instead).
Since we never trust our users and the data in forms comes from users, we can’t trust that it is valid.
So, a big responsibility of a Form is to clean its data. We maintain a clear separation between:
Raw data, that can not be trusted, and
Cleaned data, that has been validated and sanitized.
When implementing save(), for example, we access only the safe cleaned version, never the raw data.
COMP3297: Software Engineering 11
Bound and Valid
There are three possible states a Form can be in:
It either has user data or it doesn’t.
If it has user data, those data are either clean, or they aren’t
A Form that has user data is Bound. The is_bound attribute is True.
The Form’s is_valid() method causes a Form’s data to be validated and cleaned. It returns True only if the data are clean. Clearly, a Form can only be valid if it is bound.
A cleaned_data dictionary is created during validation and cleaning. This contains the safe data we access and use.
An errors dictionary contains the errors detected in data that did not validate successfully.
COMP3297: Software Engineering 12
Customizing validation
We can make is_valid() do whatever we want.
There are two kinds of methods executed during validation:
Validator methods. Clean methods.
Django provides validator methods for its field types. So when we customize, it is by providing custom clean methods.
Example: The Course model class specifies that lists of Course objects should be ordered by Code. Lower-case Codes will mess up the intended ordering.
We can provide a clean method to convert to upper-case any lower-case Codes supplied by the user during Course creation.
COMP3297: Software Engineering 13
Before
COMP3297: Software Engineering 14
Example. Derived from Form
COMP3297: Software Engineering 15
Fields typically mirror those of the corresponding Model class
Custom clean method.
Clean methods for fields are named: clean_
Typical save() method.
Note, the values used to initialize the instance fields are from the cleaned_data dict
save() methods are expected to return the newly created object.
After
COMP3297: Software Engineering
16
Reducing duplication with ModelForms
Since Forms often closely follow the structure of the Models they serve, it would be convenient if we could connect the Form to the Model.
This is supported by the ModelForm class. Now it is no longer necessary to declare the Form fields, and the save() method is also generated for us.
In fact, this was the class used in the previous example, because
CreateView works with ModelForms, not Forms.
COMP3297: Software Engineering 17
Forms and Templates
There are many ways to render a form as HTML depending on how much control the developer wants over the process.
Recall, each field type has an HTML representation – either the default for the type or a widget specified by the developer.
Generally, for each field in the form, we want to loop over and output: any errors, a label, and the field’s value. We can iterate over the fields in a form and do that as follows:
COMP3297: Software Engineering 18
{% for field in form %} {{ field.errors }}
{{ field.label_tag }} {{ field }}
…
Forms and Templates
A common approach is to use one of the following shortcuts at first, and then customize as needed.
Each shortcut displays the fields of a form in the order in which they were defined in the form class:
Form.as_p()
Render as a series of
tags, with each containing one field
Form.as_ul()
Render as a series of
Form.as_table()
Render as a