Skip to content

9. Create Django form to take in user input and send back model prediction

Katie House edited this page Sep 16, 2020 · 4 revisions

First create a django form class in a new file iris/forms.py for which each attribute is the expected user input to your model:

from django import forms

class ModelForm(forms.Form):
    sepal_length = forms.DecimalField(label='Sepal Length (cm)', decimal_places=2, max_digits=3)
    sepal_width = forms.DecimalField(label='Sepal Width (cm)', decimal_places=2, max_digits=3)
    petal_length = forms.DecimalField(label='Pedal Length (cm)', decimal_places=2, max_digits=3)
    petal_width = forms.DecimalField(label='Pedal Width (cm)', decimal_places=2, max_digits=3)

Django forms make it easy to define form inputs and perform data validation.

Then, update the iris/views.py and replace the home() function with a predict_model() function. The predict_model view is run when the user hits the landing page. When the landing page is loaded, there is a HTTP GET request to show the blank form. When the "submit" button is clicked, there is a HTTP POST request to send back the predicted class.

from django.shortcuts import render
from .forms import ModelForm


def predict_model(request):
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = ModelForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required
            sepal_length = form.cleaned_data['sepal_length']
            sepal_width = form.cleaned_data['sepal_width']
            petal_length = form.cleaned_data['petal_length']
            petal_width = form.cleaned_data['petal_width']

            # give prediction response
            prediction = "MyPrediction"
            return render(request, 'home.html', {'form': form, 'prediction': prediction})

    # if a GET (or any other method) we'll create a blank form
    else:
        form = ModelForm()

    return render(request, 'home.html', {'form': form})

the render() function returns an HTTPResponse object that is rendered in the home.html template. The third argument in the render() function, or {'form': form} and {'form': form, 'prediction': prediction} is called "context". This is data you want to send back to the html template. For example, {'form': form} sends back the ModelForm object that can be accessed in the home.html file with {{form}}. Similarly, {'form': form, 'prediction': prediction} also sends back the "MyPrediction" string that is rendered with {{prediction}}.

Update your mysite/urls.py with the new view:

from django.contrib import admin
from django.urls import path
from iris import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.predict_model, name='predict_model'),
]

Lastly, edit the iris/templates/home.html so that you can view the new form and the prediction:

{% extends 'base.html' %}

{% block content %}
<form action="" method="post">
    {% csrf_token %}
    {{ form }}
    <input type="submit" value="Submit">
</form>

{% if form.is_valid %}
<p> The model predicted: <b>{{ prediction }}</b></p>
{% endif %}

{% endblock %}

Now run your app to see if it worked! You should see a blank form that validates data and sends back "My Prediction"! 😄

Now it's time to add the machine learning model! To do this, you make a couple edits in iris/views.py

Add pickle to the import statements:

import pickle

in if form.is_valid(): use the model.predict method on the user inputs:

# Run new features through ML model
model_features = [
    [sepal_length, sepal_width, petal_length, petal_width]]
loaded_model = pickle.load(
    open("ml_model/iris_model.pkl", 'rb'))
prediction = loaded_model.predict(model_features)[0]

The revised iris/views.py will now look like this:

from django.shortcuts import render
from .forms import ModelForm
import pickle


def predict_model(request):
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = ModelForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required
            sepal_length = form.cleaned_data['sepal_length']
            sepal_width = form.cleaned_data['sepal_width']
            petal_length = form.cleaned_data['petal_length']
            petal_width = form.cleaned_data['petal_width']

            # Run new features through ML model
            model_features = [
                [sepal_length, sepal_width, petal_length, petal_width]]
            loaded_model = pickle.load(
                open("ml_model/iris_model.pkl", 'rb'))
            prediction = loaded_model.predict(model_features)[0]

            return render(request, 'home.html', {'form': form, 'prediction': prediction})

    # if a GET (or any other method) we'll create a blank form
    else:
        form = ModelForm()

    return render(request, 'home.html', {'form': form})

Your model is now predicting user inputs!

Clone this wiki locally