Weather API With Python and Flask Part 3

LegionScript
5 min readSep 14, 2020

--

Video Tutorial

Code on Github

In the last installment of this tutorial series, we created the html templates that we are going to use to build this weather web app. Let’s begin by starting with the app.py file we had in Part One. It should look like this code example:

from flask import Flaskapp = Flask(__name__)
@app.route("/")
def index():
return "Hello World"

Let’s delete the ”Hello World” text to start. Now lets render the index.html template.

from flask import Flask, render_template, request
import requests
import json
app = Flask(__name__)
@app.route("/", methods=['GET', 'POST'])
def index():
return render_template("index.html")

We first needed to import the render_template function. We also import requests and json which we will use later. We then can use this function to render a template by just passing the name of the file as a parameter. We also need to tell Flask that we want to allow the post method on this index view. We will need to check for this post request later to get the data. Run the server and reload the page and you should be able to see the form on the page. Of course, right now it won’t do anything but that is what we will work on next.

Before we go any further, you will need to go to openweathermap.org and sign up for a free account. Once you are signed up, sign into your account and click on the API Keys tab. Will need one of the keys on that page to continue. Now that we have an API key, we can begin making requests to the API. To make a request, we will need some information. We will need a city, country, what units we want to use (in this case that will be Fahrenheit) and our API key. The url we will create will look like this: http://api.openweathermap.org/data/2.5/weather?appid={api_key}&q={city},{country}&units=imperial with the data in the curly brackets being replaced with our data. You can find these urls in the documentation of the API. Let’s begin building this URL.

from flask import Flask, render_template, request
import requests
import json
app = Flask(__name__)
@app.route("/", methods=['GET', 'POST'])
def index():
if request.method == "POST":
city = request.form['city']
country = request.form['country']
api_key = "#####################"
weather_url = requests.get(
f'http://api.openweathermap.org/data/2.5/weather?appid={api_key}&q={city},{country}&units=imperial')

This is how the beginning of our index function should look. We are first checking for a post request, if we get a post request then we run the code in this if statement. We grab the data submitted by the user in the form by grabbing the name we set in the HTML. We also set a variable that contains our API key. After that, we make a request using the requests library and pass in the url as the parameter. In this example I made use of an f string which makes string formatting super easy. You just need to put an f in front of the string and then pass variables in between curly brackets. At this point we have pulled the weather data from the API.

{
"coord": {
"lon": -86.16,
"lat": 39.77
},
"weather": [
{
"id": 803,
"main": "Clouds",
"description": "broken clouds",
"icon": "04d"
}
],
"base": "stations",
"main": {
"temp": 53.08,
"pressure": 1008,
"humidity": 62,
"temp_min": 51.01,
"temp_max": 55.4
},
"visibility": 16093,
"wind": {
"speed": 20.8,
"deg": 230,
"gust": 33.33
},
"rain": {},
"clouds": {
"all": 75
},
"dt": 1571758081,
"sys": {
"type": 1,
"id": 4533,
"country": "US",
"sunrise": 1571745712,
"sunset": 1571784965
},
"timezone": -14400,
"id": 4259418,
"name": "Indianapolis",
"cod": 200
}

You can see in the data above the different weather information we could use in our application. But before we can pull data out of the json we need to use the json library to convert the data into python objects like dictionaries and lists. From that point we can go get the data we need.

from flask import Flask, render_template, request
import requests
import json
app = Flask(__name__)
@app.route("/", methods=['GET', 'POST'])
def index():
if request.method == "POST":
city = request.form['city']
country = request.form['country']
api_key = "#####################"
weather_url = requests.get(
f'http://api.openweathermap.org/data/2.5/weather?appid={api_key}&q={city},{country}&units=imperial')
weather_data = weather_url.json() temp = round(weather_data['main']['temp'])
humidity = weather_data['main']['humidity']
wind_speed = weather_data['wind']['speed']
return render_template("result.html", temp=temp, humidity=humidity, wind_speed=wind_speed, city=city) return render_template("index.html")

weather_data = weather_url.json() converts the data. From there you can go layer by layer to find the data we need, first we write the variable name of whats holding the data. Next, go to the next indentation level, find what is holding the piece of data you want. In the case of the temperature ‘main’ is holding that. Go to the next indentation level, ‘temp’ is holding the temperature and is a key value pair so that is where we stop. We can write weather_data[‘main’][‘temp’] to get the temperature value. We also round it to the nearest whole number with the built in round() function. This is just a normal python dictionary and works like any other dictionary. We can repeat that for humidity and wind_speed. Finally, we render a different template if a post request a result.html. We also pass in the three variables to this function as well. This will allow us to write this data into the template.

Lets quickly create a result.html template using our base template like we did for the index.html template.

{% extends 'base.html' %}
{% block content %}
<div class="main" style="background-color: #f5f5f5; background-repeat: no-repeat; background-position: center; background-size: cover; height: 100vh;">
<div class="container h-100">
<div class="row justify-content-center">
<div class="col-md-6 col-sm-12 col-6-12 pt-5">
<div class="card border-0 p-3 shadow-sm text-center">
<h3>Current Weather For {{ city }}</h3>
<h5>Temperature: {{ temp }} F</h5>
<h5>Humidity: {{ humidity }}%</h5>
<h5>Wind Speed: {{ wind_speed }} mph</h5>
</div>
</div>
</div>
</div>
</div>
{% endblock content %}

This template should look very similar to the index.html except instead of a form we are just displaying some text. You will see something that is a little different than before. Instead of a Jinja2 syntax of {% %}. You will see {{ }}. This is the syntax Jinja2 uses to pass in variables into a template. So we can pass any variable we passed into our render_template function here into our template. This is how we will display the weather data that we grabbed from the JSON data earlier. Other than that it is just basic HTML using the {% extends ‘base.html’ %} to use the base.html as our base template.

Go ahead and reload the application and enter a city and country. You should get some weather data displayed for you. This is where we are going to stop this tutorial. You could keep going with this project and add more advanced styling or change what data is being displayed by grabbing different values in the JSON data if you would like. There are also many different Javascript libraries out there you could use to add animation, hover effects, etc if you are looking for another challenge. Hopefully this has been a good introduction to using the Flask microframework and using API’s to create a complete web application.

--

--

No responses yet