Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Flask 101: How to Add a Search Form

DZone's Guide to

Flask 101: How to Add a Search Form

In this post, we take a look at how to add a search form to your Flask-based web application. Read on for the awesome tutorial.

· Web Dev Zone ·
Free Resource

Bugsnag monitors application stability, so you can make data-driven decisions on whether you should be building new features, or fixing bugs. Learn more.

In our last article, we added a database to our Flask web application but didn’t have a way to add anything to our database. We also didn’t have a way to view anything, so, basically, we ended up having a pretty useless web application. This article will take the time to teach you how to do the following:

  • Create a form to add data to our database.
  • Use a form to edit data in our database.
  • Create some kind of view of what’s in the database.

Adding forms to Flask is pretty easy too, once you figure out what extension to install. I had heard good things about WTForms so I will be using that in this tutorial. To install WTForms you will need to install Flask-WTF. Installing Flask-WTF is pretty easy; just open up your terminal and activate the virtual environment we set up in our first tutorial. Then run the following command using pip:

pip install Flask-WTF

This will install WTForms and Flask-WTF (along with any dependencies) to your web app’s virtual environment.

Serving HTML Files

Originally when I started this series, all I was serving up on the index page of our web application was a string. We should probably spruce that up a bit and use an actual HTML file. Create a folder called “templates” inside the “musicdb” folder. Now create a file called “index.html” inside the “templates” folder and put the following contents in it:

<doctype html>
<head>
    <title>Flask Music Database</title>
</head>

<h2>Flask Music Database</h2>

Now before we update our web application code, let’s go ahead and create a search form for filtering our music database’s results.

Adding a Search Form

When working with a database, you will want a way to search for items in it. Fortunately creating a search form with WTForms is really easy. Create a Python script called “forms.py” and save it to the “musicdb” folder with the following contents:

# forms.py

from wtforms import Form, StringField, SelectField

class MusicSearchForm(Form):
    choices = [('Artist', 'Artist'),
               ('Album', 'Album'),
               ('Publisher', 'Publisher')]
    select = SelectField('Search for music:', choices=choices)
    search = StringField('')

Here we just import the items we need from the wtforms module and then we subclass the Form class. In our subclass, we create a selection field (a combobox) and a string field. This allows us to filter our search to the Artist, Album, or Publisher categories and enter a string to search for.

Now we are ready to update our main application.

Updating the Main Application

Let’s rename our web application’s script from “test.py” to “main.py” and update it so it looks like this:

# main.py

from app import app
from db_setup import init_db, db_session
from forms import MusicSearchForm
from flask import flash, render_template, request, redirect
from models import Album

init_db()


@app.route('/', methods=['GET', 'POST'])
def index():
    search = MusicSearchForm(request.form)
    if request.method == 'POST':
        return search_results(search)

    return render_template('index.html', form=search)


@app.route('/results')
def search_results(search):
    results = []
    search_string = search.data['search']

    if search.data['search'] == '':
        qry = db_session.query(Album)
        results = qry.all()

    if not results:
        flash('No results found!')
        return redirect('/')
    else:
        # display results
        return render_template('results.html', results=results)

if __name__ == '__main__':
    app.run()

We changed the index() function so it works with both POST and GET requests and told it to load our MusicSearchForm. You will note that when you first load the index page of your web app, it will execute a GET and the index() function will render our index.html that we just created. Of course, we didn’t actually add the form to our index.html yet, so that search form won’t appear yet.

There is also a search_results() that we added to handle really basic searches. However, this function won’t be called until we actually implement a way to display the results. So let’s go ahead and make the search form visible to our users.

When I was learning how to create forms with WTForms, the Flask-WTF website recommended creating a template with a macro called “_formhelpers.html.” Go ahead and create a file of that name and save it to your “templates” folder. Then add the following to that file:

{% macro render_field(field) %}
    <dt>{{ field.label }}
    <dd>{{ field(**kwargs)|safe }}
    {% if field.errors %}
        <ul class=errors>
        {% for error in field.errors %}
            <li>{{ error }}</li>
        {% endfor %}
        </ul>
    {% endif %}
    </dd>
{% endmacro %}

This syntax might look a little odd since it is obviously not just HTML. This is actually Jinja2 syntax, which is the templating language used by Flask. Basically, anywhere you see the squiggly braces (i.e. {} ), you are seeing Jinja syntax. Here we pass in a field object and access its label and errors attributes. Feel free to look up the documentation for additional information.

Now open up your “index.html” file and update it so that it has the following contents:

<doctype html>
<head>
    <title>Flask Music Database</title>
</head>

<h2>Flask Music Database</h2>

{% from "_formhelpers.html" import render_field %}
<form method=post>
  <dl>
    {{ render_field(form.select) }}
    <p>
    {{ render_field(form.search) }}
  </dl>
  <p><input type=submit value=Search>
</form>

The new code in this example shows how you can import the macro you created into your other HTML file. Next, we set the form method to post and we pass the select widget and the search widget to our render_field macro. We also create a submit button with the following label: Search. When you press the Search button, it will post the data in the other two fields of the form to the page that it is on, which in this case is our index.html or “/”.

When that happens, the index() method in our main.py script will execute:

@app.route('/', methods=['GET', 'POST'])
def index():
    search = MusicSearchForm(request.form)
    if request.method == 'POST':
        return search_results(search)

    return render_template('index.html', form=search)

You will note that we check which request method it is and if it’s the POST method, then we call the search_results() function. If you actually press the Search button at this stage, you will receive an Internal Server Error because we haven’t implemented “results.html” as of yet. Anyway, right now your web application should look something like this:

Image title

Let’s take a moment and get the results function doing something useful.

Updating the Results Functionality

Right now, we don’t actually have any data in our database, so when we try to query it, we won’t get any results back. Thus we need to make our web application indicate that no results were found. To do that we need to update the “index.html” page:

<doctype html>
<head>
    <title>Flask Music Database</title>
</head>

<h2>Flask Music Database</h2>

{% with messages = get_flashed_messages() %}
  {% if messages %}
    <ul class=flashes>
    {% for message in messages %}
      <li>{{ message }}</li>
    {% endfor %}
    </ul>
  {% endif %}
{% endwith %}

{% from "_formhelpers.html" import render_field %}
<form method=post>
  <dl>
    {{ render_field(form.select) }}
    <p>
    {{ render_field(form.search) }}
  </dl>
  <p><input type=submit value=Search>
</form>

You will note that the new code is a new block of Jinja. Here we grab “flashed” messages and display them. Now we just need to run the web application and try searching for something. If all goes as planned, you should see something like this when you do a search:

Image title

Wrapping Up

Now we have a neat little search form that we can use to search our database, although it frankly doesn’t really do all that much since our database is currently empty. In our next article, we will focus on finally creating a way to add data to the database, display search results, and edit the data too!

Download Code

Download a tarball of the code from this article: flask_musicdv_part_iii.tar

Other Articles in the Series

Related Readings

Monitor application stability with Bugsnag to decide if your engineering team should be building new features on your roadmap or fixing bugs to stabilize your application.Try it free.

Topics:
web application ,python ,flask ,web dev

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}