30. Django forms (1)

30.01 Introduction

We’re going to introduce forms in Django – a way to provide users a way to add entries to the database.

A reminder for those using Windows 10 on locating and restarting the project files, using these shell commands after navigating to the desktop:

$ cd bioweb
$ python -m venv env
$ env\Scripts\activate
* if we do a dir now we see two directories, bioweb and env
(env) $ cd bioweb
(env) $ python manage.py runserver

If we now go to http://127.0.0.1:8000/ in our browser we can see our project.

Django provides a fairly straightforward and sophisticated way to build input forms using the resource definitions in our model classes.

Let’s start by going to index.html in our genedata directory and adding this:

Create EC Entry

Add a EC Entry

By doing this we’re promising a new route on the database. We now need to go to urls.py and add this route to URLpatterns (you can see it below, on the last line before ]):

urlpatterns = [
    path('', views.index, name='index'),
    path('gene/', views.gene, name='gene'),
    path('list/', views.list, name='list'),
    path('poslist/', views.poslist, name='poslist'),
    path('delete/', views.delete, name='delete'),
    path('create_ec/', views.create_ec, name='create'),
]

We’ve wired that up to a function which we’ve called create_ec. We can now go to views.py and add this function.

def create_ec(request):
    Pass

For now we’re going to leave the function blank, so that’s why we’ve just put pass in it.

We can now create a new file called forms.py in the genedata directory. We can now create a new form quite easily.

from django import forms

class ECForm(forms.Form):
    ec_name = forms.CharField(label='EC Name', max_length=100)

Forms are populated very much like our models, so let’s have a look at our models.py. Our EC class has a single field called ec_name, of type models.CharField.

In forms.py we need to match the names of the form objects to our model’s objects.

We can go back to views.py now. In order to use our new forms object, we must import it:

from .forms import *

Now in views.py we can create the create_ec function. Each of our pages gets a copy of the genes from the left hand navigation, so let’s do that now:

    master_genes = Gene.objects.all()

This function does two different things.

When the request object arrives, if the request method is post we are going to assume that the user has sent some data to us. So in the first part of the IF clause we’re going to handle the request as though there is data.

If it’s not a POST request, we’re going to assume the user just wants to see the web page to see the web form, and we need to do something to handle that situation too, eg show the user all the entries in the EC table.

def create_ec(request):
    master_genes = Gene.objects.all()
    if request.method == 'POST':
        form = ECForm(request.POST)
        if form.is_valid():
            ec = EC()
            ec.ec_name = form.cleaned_data['ec_name']
            ec.save()
            return HttpResponseRedirect('/create_ec/')
    else:
        ecs = EC.objects.all()
        form = ECForm()
    return render(request, 'genedata/ec.html', {'form': form, 'ecs': ecs, 'master_genes': master_genes})

If POST, the form is checked to see if it’s valid, then we add the data to a new row in our table, save it and then redirect to a suitable route such as /create_ec.

The last thing to do is to build our template. Let’s create a new ec.html file in the templates/genedata folder.

As with all of our templates, we’re going to extend the base template:

{% extends "./base.html" %}

We’re also going to load all of the template tags for Bootstrap:

{% load bootstrap4 %}

Now we need to make sure that we can use Bootstrap. If you haven’t installed Bootstrap into your virtual environment go to CMD and do that, in the bioweb directory:

$ pip install django-bootstrap4==2.2.0

Then we need to go to settings.py and add bootstrap 4 as one of the apps in our project:

INSTALLED_APPS = [
    'bootstrap4',
    'genedata.apps.GenedataConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

If you don’t use Bootstrap, this is a good guide for setting up forms in Django: https://docs.djangoproject.com/en/3.0/topics/forms/

Back to our app. We now provide the content block for the page:

{% block content %}
...
{% endblock%}

We’re going to divide the page into two sections. The first section at the top shows the current state of the table data and the second section at the bottom will be our form, where we can add a new name.

As you recall, we’re passing an object called ecs so for each row in that type of list, we want to add a row to our HTML table. We’ve seen this pattern in a different template earlier.

Current EC Names

{% for ec in ecs %} {% endfor %}
EC Name
{{ ec }}

So now we need to show the form. This needs to be enclosed in form tags, and the form needs an action – a URL that we are going to send the data to. It also needs a method, which is HTTP post, and a CSS class called form so it will pick up some bootstrap. (We didn’t actually define this class in our CSS, it’s just an example)

...

To make the form work we need a couple more things. We need a security token, which we’ll discuss in a future blog post.

    {% csrf_token %}

And we need a template tag to show the actual form, and a button for the user to click:

    {% bootstrap_form form %}
    

So did it all work? Let’s look at the main page of our site:

We can see a new heading and link for Add a EC entry. If we click it:

You can see a new form (not very pretty!) where we can add a new gene. If we now type in the gene and add it, we can see it appear on the gene list.

Wednesday 17 November 2021, 15 views


Leave a Reply

Your email address will not be published. Required fields are marked *