Build Website with Flask – Part 6


This is part of our Flask series:

Story: Assume you work in the IT Department of Right-On Realtors. Your boss asks you to create a simple website the Realtors can query to view current Home Sales.

He would like this website created using the Flask plugin.

What is Flask?

Flask is a web app framework created with ease of use in mind. Without much training, you can easily create a simple web application. Flask works with Bootstrap, HTML, CSS, and Jinja (to name a few) to create a website.


Preparation

This article assumes you have completed the following from Part 1, Part 2, Part 3, Part 4, and Part 5:

  • Created and Activated a Virtual Environment.
  • Installed all of the required plugins.
  • Created the appropriate folder structure.
  • Created and saved an app.py file to the realtors folder.
    ο»Ώ
  • Added Routes to the app.py file.
  • Added Jinja to the base template.
  • Created and saved HTML files to the realtors/templates folder.
    ο»Ώ
  • Linked to Bootstrap.
  • Added a Bootstrap Navbar to the base template file (base.html).
  • Added Jinja to the HTML pages.
  • Viewed the website in a Browser.
  • Added a Form with elements to an HTML page.
  • Added Jinja to the Reports page.
  • Added code to app.py to get the HTML Form working.
  • Read in the Real Estate CSV file to a DataFrame.
  • Queried the results based on a Zip Code.
  • Displayed the results on the Reports page.

In Part 6, you will learn how to:

  • Validate the Zip Code.
  • Clean-Up the Data.
  • Correct the Sales Prices.
  • Format the Sales Prices.
  • Update the Navbar.

Add the following code to the top of each code snippet. This snippet will allow the code in this article to run error-free.

import pandas as pd
from flask import Flask, render_template, request

Validate the Zip Code

If you enter an invalid Zip Code on the Home page (index.html), the Reports page displays only the header row (column names) of the DataFrame. Let’s modify the code to correct this issue.

The options are:

  1. Redirect them back to the Home page (index.html) with no error message, or
  2. Redirect them back to the Home page (index.html) with an error message, or
  3. Display an error message on the Reports page (reports.html) with a Back hyperlink to return to the Home page (index.html).

For this example, option three (3) is on point with our tutorial.

Add the lines highlighted in yellow, indent as needed, and save.

{% extends 'base.html' %}

{% block content %}     
   <div class='container'>
      <h2>Real Estate Transactions</h2>
      <h3>{{ zip_code }}</h3>
      <br/><br/>

      {% if myData.empty %}
         <h4>No matching entries found!</h4>
         <br/><br/>
         <a class="nav-link" aria-current="page" href="{{ url_for('index') }}">Home</a>

      {% else %}
         <table width="600">
         <thead>
            <tr>
               {% for column in myData.columns %}
                  <th>{{column}}</th>
               {% endfor -%}
            </tr>
         </thead>
         <tbody>
            {% for key,value in myData.iterrows() %}
               <tr id="row-{{key}}">
                  {% for v in value.values %}
                     <td>{{ v }}</td>
                  {% endfor %}
               </tr>
            {% endfor %}
         </tbody>
         </table>
      {% endif %}
   </div>
{% endblock %}
  • Line [1] checks to see if the DataFrame contains data. For example, if the Zip Code entered on the Home page (index.html) returned results.
  • Line [2] executes if there are no matches. A message displays on the Reports page (reports.html) indicating the same.
  • Line [3] places two (2) new lines after the message.
  • Line [4] contains a hyperlink that, when clicked, returns the user to the Home page (index.html).

The remainder of the code stays the same. However, now it resides inside an else statement. This section executes only if the DataFrame contains results.

Let’s test this!

Navigate to the Home page (index.html), enter 90210 and click the Search button. The output should display as follows.

Now let’s enter a Zip Code that does exist, 95842. Repeat the steps above. The output should display as follows:

Excellent!


Clean-Up the Data

Upon reviewing the data, you know your boss would not like the data in uppercase. Let’s correct this by changing the case for the street, and city columns.

Add the lines highlighted in yellow and save.

app = Flask(__name__)

@app.route('/')                               # home
def index():
    return render_template('index.html')

@app.route('/reports', methods=['POST'])      # reports
def reports():
    cols = ['street', 'city',  'zip', 'beds', 'baths', 'sq__ft', 'price']
    zip_code = request.form.get('zip_code', type=int)
    myData = (pd.read_csv('real-estate.csv', usecols=cols)[lambda x: x['zip'] == zip_code])
    
    myData['street'] = myData['street'].apply(lambda x: x.title())
    myData['city'] = myData['city'].apply(lambda x: x.title())

    return render_template('reports.html', zip_code=zip_code, myData=myData)

@app.route('/contact')                        # contact
def contact():
    return render_template('contact.html')

Line [1] and Line [2] does the following:

  • References the DataFrame column to modify.
  • Applies lambda to modify each column entry to Title Case.
  • Saves the updated entries to the referenced DataFrame column.

Let’s run the code. Enter 95842 and click the Search button. The output should display as follows:

Much better!


Correct the Sales Prices

The price column appears to be missing a zero (0) at the end of each entry. These prices are too low for the Sacramento area!

Add the line highlighted in yellow and save.

app = Flask(__name__)

@app.route('/')                               # home
def index():
    return render_template('index.html')

@app.route('/reports', methods=['POST'])      # reports
def reports():
    cols = ['street', 'city',  'zip', 'beds', 'baths', 'sq__ft', 'price']
    zip_code = request.form.get('zip_code', type=int)
    myData = (pd.read_csv('real-estate.csv', usecols=cols)[lambda x: x['zip'] == zip_code])
    
    myData['street'] = myData['street'].apply(lambda x: x.title())
    myData['city']   = myData['city'].apply(lambda x: x.title())
    myData['price']  = myData['price'].apply(lambda x: x*100)
    
    return render_template('reports.html', zip_code=zip_code, myData=myData)

@app.route('/contact')                        # contact
def contact():
    return render_template('contact.html')

By applying a lambda each price is multiplied by 100.

Next, run the code and view the changes.

The output should display as follows:

Looking good!


Format the Sales Prices

The report would look better if the price column had a currency symbol, comma separator, and decimal place. Let’s correct this.

Add the line highlighted in yellow and save.

app = Flask(__name__)

@app.route('/')                               # home
def index():
    return render_template('index.html')

@app.route('/reports', methods=['POST'])      # reports
def reports():
    cols = ['street', 'city',  'zip', 'beds', 'baths', 'sq__ft', 'price']
    zip_code = request.form.get('zip_code', type=int)
    myData = (pd.read_csv('real-estate.csv', usecols=cols)[lambda x: x['zip'] == zip_code])
    
    myData['street'] = myData['street'].apply(lambda x: x.title())
    myData['city']   = myData['city'].apply(lambda x: x.title())
    myData['price']  = myData['price'].apply(lambda x: x*100).apply(lambda x: f"${x:,.2f}")
    
    return render_template('reports.html', zip_code=zip_code, myData=myData)

@app.route('/contact')                        # contact
def contact():
    return render_template('contact.html')

By using a lambda, each price entry is formatted.

Run the code to view the new price format.

The output should display as follows:


Update the Navbar

After reviewing the code, you notice that the Navbar contains the Reports menu item. It turns out we don’t need that item. Let’s remove it.

Navigate to and open the base.html file. Remove the <li></li> tags shown below.

Save and run.

            <li class="nav-item">
              <a class="nav-link" href="{{ url_for('reports') }}">Reports</a>
            </li>

If successful, the Navbar should be as follows:

πŸ’‘ Note: To view any changes, Flask needs to be re-started. To perform this task, navigate to the command prompt and enter CTRL+C (stop), then flask run (re-start).


Summary

In this article, you learned how to:

  • Validate the Zip Code.
  • Clean-Up the Data.
  • Correct the Sales Prices.
  • Format the Sales Prices.
  • Update the Navbar.

What’s Next

In Part 7 of this series, we will:

  • Add a Stylesheet.
  • Apply styles to the Navbar.
  • Apply styles to the HTML pages.