How I Built a Weather App Using Python Flask

In the first part of this series tutorial, we learned how to build a weather app using Django, a powerful Python framework for building web applications. Although not a prerequisite to understanding this second part, learning how to design such an application is worth your time.

For the very first time, I will be explaining how I design an application using the Flask framework. Like Django, Flask is a web application framework written in Python. Unlike, Django, it is easy to get started as a beginner. In just seven lines of code, you will write your first introduction to the framework, the 'Hello, World!' code.

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

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

This is all that is required. If you save it in a file called app.py; and run python3 app.py in your terminal, you will see the app running on your local server. Can you see how simple it is? If this was Django, it would require more boilerplate code.

So, in this tutorial, we will learn how to build a weather app using the Flask framework. There is no doubt that building projects using Flask will help you learn and master the framework.

As mentioned in the first part of this series, a weather application is used to get real-time weather information based on cities selected. I assume by now you must have received your API key from OpenWeatherMap. If not, please do well to register on the platform to receive your API key which we will use in this tutorial.

Prerequisites

Although this project tutorial is for beginners, you will benefit greatly if you have basic knowledge of Flask. An excellent resource I recommend if you want to go from a beginner to an advanced Flask developer is The Flask Mega Tutorial by Miguel Grinberg.

Setting up Flask

We will first create and activate a virtual environment, which is considered best practice, before installing Flask.

Create and cd into a new folder

mkdir flask_project && cd flask_project

Create and activate a virtual environment

python3 -m venv venv
source venv/bin/activate

Install Flask

pip install flask

Install the python-dotenv package to register the environment variable

pip install python=dotenv

Create a requirements.txt file to store the dependencies used in this project.

pip freeze > requirements.txt

Starting Flask: A Simple Hello World

Consider the 7 lines of code mentioned above. We import the Flask class from the flask package. The app variable creates the application object as an instance of the Flask class. The __name__ variable configures Flask; and helps it know when and where to find template files.

The hello_world() function has a Python decorator @app.route. Remember, a Python decorator modifies a function. Thus, it is used to register and link the URL (/) to the function so that when the URL is requested by a web browser, Flask can easily invoke the function and pass the return value to the browser. Therefore, we can rightly say that a route is the different URLs implemented by the Flask application.

Speaking of templates, they are HTML files written separately and stored in a templates folder. So, instead of directly writing the 'Hello, World!' in the function, we can write it in a template file and renders it to the browser.

To demonstrate what I’m talking about, create a template folder. Inside the folder, create an HTML file with the name index.html, and write the following:

<div>
   <p>Hello, World!</p>
</div>

Then update the app.py.

from flask import Flask, render_template

app = Flask(__name__)

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

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

Run python3 app.py to see the "Hello, World!" now rendered from a template file. This was made possible by the render_template() function. This is the process we will follow to create the weather app.

Creating a Form

To start building the weather app, we have to create a form. Update the index.html file with the following HTML code.

<html lang="en">
  <head>
    <title>Weather App</title>
  </head>
  <body>
    <h1>Weather App!</h1>
    <form method="POST" action="{{ url_for('get_weather')}}">
      <input name="city" type="text" value="{{ request.form['city'] }}">
      <button type="submit">Search</button>
    </form>
    {% if data %}
      <p>You have entered: {{ city }}. Country: {{ data['sys']['country'] }}</p>
      <p>Temperature: {{ data['main']['temp'] }}Β°C</p>
      <p>Temperature feeling: {{ data['main']['feels_like']Β°C }}</p>
      <p>Pressure: {{ data['main']['pressure'] }}hPa</p>
      <p>Humidity: {{ data['main']['humidity'] }}</p>
      {% for i in data['weather'] %}
       <p>Description: {{ i['description'] }}</p>
      {% endfor %}
    {% endif %}
  </body>
</html>

A lot of things are going on here. We use the form element to create a form with the method equal to POST. When the submit button is clicked, a request is made with the POST method which makes it possible to collect input values to be accessed in our Python file.

Using the {{ request.form['city'] }} syntax, Flask can easily pick this value in our Python code for further use.

However, all these won’t work without the action property in the form element, that is the get_weather() function.

Getting Weather Data

Update your app.py with the following code to create the get_weather() function.

from flask import Flask, render_template, request
import requests
from openweather import KEY

@app.route('/city', methods=('GET', 'POST'))
def get_weather():
    if request.method == 'POST':
        city = request.form['city']
        url = f'https://api.openweathermap.org/data/2.5/weather?q={city}&units=metric&appid={KEY}'
        res = request.get(url)
        data = res.json()
        return render_template('index.html', city=city, data=data)
    return render_template('index.html')

The function is decorated with @app.route which I have already explained. We set the route to be '/city'. If the request method is POST, the input value will be read and saved to the city variable. Next, we use the requests module to request the URL; and save the response to the res variable. Then we convert the response to a Python dictionary object using res.json(); and save it to the data variable.

Finally, we display the result to our template using the render_template() function. Notice we passed the city and data variables as arguments to render_template.

If the request method is otherwise, we simply display the template containing the empty form. Before I explain other things here, let’s go back to our index.html file.

The {{ … }} placeholder is used to display dynamic content to the template file. Flask as we know, depends on the Jinja2 template engine. When render_template is called, it equally calls the Jinja2 template engine which substitutes the {{ … }} block with the values provided in the render_template() function.

Jinja2 also supports conditional statements and forloops given inside the {% … %} blocks. In that template file, we say, if the data variable is given, display the contents in the p element. Then, we close the conditional statement and the for loop structure.

The conditional statement is important, without which you will get the following error:

Jinja2.exceptions.UndefinedError:
data is undefined

This error arises when we try to access a key from a non-existing object. So, do not forget the conditional statement.

The API Key

As mentioned earlier, to make an API call to OpenWeatherMap, you need an API key. Having gotten your API key, you have to keep it safe. Notice how we did in the app.py file. First of all, you create a file called openweather.py. Inside the file, make it look like this:

KEY = 'Your API Key'

Replace the text in quotes with your API key. Can you then see how we imported it to the app.py without exposing the key? If you are deploying this app, you may have to create a .gitignore folder where all sensitive data will be kept to avoid exposing them.

Finally, create a file and name it .flaskenv. In this file, we will register the FLASK_APPΒ  environment variable so that we will not always have to set the environment variable when we run the flask command. Inside the file, write the following:

FLASK_APP=app.py

That’s all. We are done. Now run the flask command like this to test the app:

flask run

If you go to http://127.0.0.1:5000/city in your browser; and type a city of your choice, you will see something similar to the image below.

Conclusion

Congratulation on creating a weather app using the Flask framework. You have undoubtedly learned something or two you can add to your knowledge as you continue your web development journey.

You will observe that I added only a little CSS styling so we can focus on the major task. The code is available on my GitHub page. In the final part of this series tutorial, we will learn how to create this app using Streamlit.

.