# How to add a Django form to a project

All of our Code for Life projects use the free, open source Django framework, which means it’s really worthwhile for us to get to grips with the framework’s architecture. One of the many benefits of Django is that it provides a form handling service (for a general tutorial on Django forms, click here).

Like most websites, the Code for Life portal includes forms for logging in, registering and contacting the Ocado Technology team responsible for the project.

This tutorial will take you through how forms are organised, using the above mentioned website as an example.

## Create the form class

First, you need to create your all important form class using a Python file: this will contain your form’s widgets, and will dictate the logic behind the data validation.

1. Go to the forms folder. Here are the files which contain the forms of the project.

2. Choose the file which is relevant to your form – ie: in the portal project, the teach.py file defines all
forms that a teacher requires. If there is no suitable file, create it!

3. Define your form class like so:

class FormName(forms.Form):

4. Define the widgets
This is where you decide on what fields to include within your form, and their properties. For example the code below defines a field (an input box) for entering your first name and sets a maximum character limit of 100 as a property of that field:

first_name = forms.CharField(
label=”First name”,
max_length=100,
widget=forms.TextInput(
attrs={
‘placeholder:’ ‘Grace’
}
)
)

From the user’s perspective they will see the input field for their first name and a placeholder ‘Grace’ which helps them to understand how to fill in the box, if they are struggling to remember what a ‘first name’ is…

Have a look around the current forms to find out how to define other widgets, such as email fields, drop downs, password fields, etc.

5. Define methods for validation.
This is where you should handle things like making sure:
– A unique field isn’t entered twice

When the data inputted isn’t valid, you may raise the following error:

raise forms.ValidationError(“error message”)

Your form class is now complete. Go celebrate with a nice cup of tea.

## Define the view (form functionality)

Now you have to code what it is that you want the form to do. This is where data processing, sanitisation, models creation and redirections happen.

1. Go to the views folder. Here are the files which contain the views of the project.

2. Choose the file which is relevant to your form. In the example of the code for life portal project, this is once again the teach.py file.

3. Define your method for form handling:

def method_name(request):

Feel free to add any other arguments that you might require to process your form.

4. If your form deals with handling sensitive data and/or changing the state of your app, then it has to do this through a POST request (POST requests submit data to be processed, from an HTML form to the identified resource):

if request.method == ‘POST’:
#data handling

5. Import the form you’ve just created:

from portal.forms.teach import FormName

6. Call the form class you’ve just imported:

form_name = FormName(request.POST)

You can now use the form_name variable to perform checks, such as whether the form is valid upon submission.

7. Define the HTTP redirect once the form is valid and submitted. There are two ways of doing so:

return HttpResponseRedirect(reverse_lazy(‘url_name’))

Or:

return render(request, ‘path/to/template/file’,
{‘HTML_attr1’: attr_name1,
‘HTML_attr2’: attr_name2})

There are a couple of things to note here.

– The first method is a simple redirect to a page, which doesn’t require you sending any attributesto the HTML (more on this later).
– In this case, the ‘url_name’ value is the url name of your web page, as defined in the urls.py file (more on this later).

– The second method does the exact same thing, but also offers the possibility of sending some attributes to the HTML, which can be used within the HTML code when that page is rendered.
– The ‘path/to/template/file’ is the file path to the HTML file that contains the code for the page you want to render, found in the templates folder.

In the second case you have to pass in the form name as one of the HTML attributes, so the HTML page can know which form to show on the page. In the end, it would look something like this:

return render(request, ‘path/to/template/file’,
{‘form_name_attr’: form_name,
#other attributes})

## Call the Python method in the URLs file

This is where you indicate that you want this form to show up at a specific URL.

1. Navigate to urls.py

2. Import the Python method you just created.

3. Create a new URL like so:

url(url_regex, method_name, name=”url_name”),

Where ‘url_regex’ is the pattern for your in-browser URL, method_name is your method you just defined, and url_name is the name of the URL you want to give it. The ‘url_name’ value is what is used in the ‘request_lazy(‘url_name’) seen earlier.

## Add the form in HTML

Now all that’s missing is the actual form within the HTML page.

1. Navigate to the templates folder and choose the HTML file you want your form to be in (if it doesn’t exist, create it!).

2. Create the form tag in HTML:

<form>
...
</form>

3. If the form handles a POST request, make sure to add:

<form method=”post”>

{% csrf token %}

</form>

4. Add the form fields using the HTML attributes passed from the Python method:

For example:

{{ form_name_attr.first_name }}
{{ form_name_attr.first_name.errors }}

This tells the HTML to add the ‘first_name’ text field of your form (see step 1 of this blog), followed by the error messages that can arise from invalid data input.

5. Add a submit button to submit the form:

<button type=”submit” name=”form_purpose”>Submit</button>


The important bit here is the type=“submit” which is what indicates that, upon pressing the button, the logic within the Python method gets launched and the form data is processed.

NB: The name attribute comes in handy if you have many forms on one page and need to differentiate between them in the Python method.

And here you have it!