Demo Application

Learn how to integrate the AccuWeather APIs in a simple Django weather application.

In this lesson, we see a simple weather application built using Bootstrap and AccuWeather APIs with the Python-based web framework, Django. This application provides us with current weather information. Moreover, it provides hourly forecasts for a period of 12 hours and daily weather forecasts for a period of 5 days for locations of our choice.

Running the application

Step 1: Click the "Run" button to start the application. Click the URL next to "Your app can be found at:" in the widget below to open the application in a new tab.

Step 2: Once the server starts, we see a homepage with a search bar. Enter a location in the format requested (City, Country).

Note: It is recommended to select a location from the list which is automatically populated in the textbox.

Step 3: After entering the location in the search bar, press "Enter" or click the search icon.

Step 4: We now see three tabs, one each for "Current Weather," "Hourly Forecasts," and "Daily Forecasts." Switch between tabs to check out the corresponding weather data.

Application code

from django.http import JsonResponse
from django.shortcuts import render
import requests
import re

API_KEY = '{{API_KEY}}'

def getCurrentConditions(locationKey):
    url = 'http://dataservice.accuweather.com/currentconditions/v1/' + str(locationKey) + '?apikey=' + API_KEY + '&details=true'

    response = requests.get(url)

    currentConditions = dict()
    currentConditions['status'] = False

    if response.status_code == 200:
        data = response.json()[0]

        currentConditions['status'] = True
        currentConditions['currentTemperature'] = data['ApparentTemperature']['Imperial']['Value']
        currentConditions['weatherIcon'] = 'https://developer.accuweather.com/sites/default/files/' + str(data['WeatherIcon']).zfill(2) + '-s.png'
        currentConditions['weatherText'] = str(data['WeatherText'])
        currentConditions['wind'] = str(data['Wind']['Speed']['Imperial']['Value']) + ' ' + str(data['Wind']['Speed']['Imperial']['Unit']) + '-' + str(data['Wind']['Direction']['Degrees']) + ' ' + str(data['Wind']['Direction']['English'])
        currentConditions['cloudCover'] = str(data['CloudCover'])
        currentConditions['dewPoint'] = str(data['DewPoint']['Imperial']['Value'])
        currentConditions['humidity'] = str(data['RelativeHumidity'])
        currentConditions['uvIndex'] = str(data['UVIndex']) + ' - ' + str(data['UVIndexText'])
        currentConditions['realTemperature'] = str(data['RealFeelTemperature']['Imperial']['Value'])
        currentConditions['precipitation'] = str(data['HasPrecipitation'])

    else:
        currentConditions['message'] = f'{response.status_code}: {response.reason}'
    
    return currentConditions


def getHourlyForecasts(locationKey):
    url = 'http://dataservice.accuweather.com/forecasts/v1/hourly/12hour/' + str(locationKey) + '?apikey=' + API_KEY + '&details=true'

    hourlyForecasts = dict()
    hourlyForecasts['status'] = False
    hourlyForecastsData = []

    response = requests.get(url)

    if response.status_code == 200:
        data = response.json()

        hourlyForecasts['status'] = True

        for i in data:
            hour = dict()
            
            hour['status'] = True
            hour['date'] = str(i['DateTime']).split('T')[0]
            hour['time'] = str(i['DateTime']).split('T')[1].split('+')[0]
            hour['weather'] = str(i['Temperature']['Value']) + '\N{DEGREE SIGN} F - ' + str(i['IconPhrase'])
            hour['rainProbability'] = str(i['RainProbability'])
            hour['weatherIcon'] = 'https://developer.accuweather.com/sites/default/files/' + str(i['WeatherIcon']).zfill(2) + '-s.png'
            
            hourlyForecastsData.append(hour)
        
        hourlyForecasts['data'] = hourlyForecastsData

    else:
        hourlyForecasts['message'] = f'{response.status_code}: {response.reason}'
    
    return hourlyForecasts


def getDailyForecasts(locationKey):
    url = 'http://dataservice.accuweather.com/forecasts/v1/daily/5day/' + str(locationKey) + '?apikey=' + API_KEY + '&details=true'

    dailyForecasts = dict()
    dailyForecasts['status'] = False
    dailyForecastsData = []

    response = requests.get(url)

    if response.status_code == 200:
        data = response.json()

        dailyForecasts['status'] = True

        for i in data['DailyForecasts']:
            day = dict()
            
            day['status'] = True
            day['date'] = str(i['Date']).split('T')[0]
            day['time'] = str(i['Date']).split('T')[1].split('+')[0]
            day['weather'] =   str(i['Temperature']['Maximum']['Value']) + '\N{DEGREE SIGN} F / ' + str(i['Temperature']['Minimum']['Value']) + '\N{DEGREE SIGN} F - ' + str(i['Day']['ShortPhrase'])
            day['rainProbability'] = str(i['Day']['RainProbability'])
            day['weatherIcon'] = 'https://developer.accuweather.com/sites/default/files/' + str(i['Day']['Icon']).zfill(2) + '-s.png'
            
            dailyForecastsData.append(day)
        
        dailyForecasts['data'] = dailyForecastsData

    else:
        dailyForecasts['message'] = f'{response.status_code}: {response.reason}'

    return dailyForecasts


def getLocationKey(location):
    locationData = dict()
    locationData['status'] = False

    if not re.match(r"[^\s,]+(?:\s*[^\s]+)*,\s[^\s,]+(?:\s*[^\s]+)*$", location):
        locationData['message'] = 'Invalid input format!'
        return locationData
    
    input = location.split()
    city = input[0][:-1]
    country = input[1].lstrip()

    url = 'http://dataservice.accuweather.com/locations/v1/cities/autocomplete?apikey=' + API_KEY + '&q=' + city
    
    response = requests.get(url)

    if response.status_code == 200:
        data = response.json()

        for i in data:
            if city.lower() == i['LocalizedName'].lower() and country.lower() == i['Country']['LocalizedName'].lower():
                locationData['location'] = i['LocalizedName'] + ', ' + i['Country']['LocalizedName']
                locationData['data'] = i['Key']
                locationData['status'] = True
        
        if locationData['status'] is False:
            locationData['message'] = 'Incorrect location entered!'

    else:
        locationData['message'] = f'{response.status_code}: {response.reason}'

    return locationData


def index(request):
    if 'term' in request.GET:
        url = 'http://dataservice.accuweather.com/locations/v1/cities/autocomplete' + '?apikey=' + API_KEY + '&q=' + request.GET.get('term')

        response = requests.get(url)
            
        locations = list()

        if response.status_code == 200:
            data = response.json()
            for i in data:
                locations.append(i['LocalizedName'] + ', ' + i['Country']['LocalizedName'])
        else:
            locations.append('No suggestions available!')

        return JsonResponse(locations, safe=False)
    
    elif request.method == 'POST':
        location = request.POST.get("location")
        locationKey = ''
        locationData = getLocationKey(location)
        status = False

        if locationData['status']:
            status = True
            location = locationData['location']
            locationKey = locationData['data']
            currentConditions = getCurrentConditions(locationKey)
            hourlyForecasts = getHourlyForecasts(locationKey)
            dailyForecasts = getDailyForecasts(locationKey)
            return render(request,'weatherapp/index.html', {'status': status, 'location': location, 'currentConditions': currentConditions, 'hourlyForecasts': hourlyForecasts, 'dailyForecasts': dailyForecasts})
        else:
            message = locationData['message']
            return render(request,'weatherapp/index.html', {'status': status, 'message': message})

    return render(request, 'weatherapp/index.html')
The weather application

Code explanation

The Autocomplete Search endpoint searches for locations as you start typing in the search box. On pressing the "Enter" key or the search icon, the getLocationKey() function given on line 105 is invoked. This function verifies the location entered and returns a corresponding location key. In case the location is not found or the API call fails, an appropriate message is returned by the function.

After retrieving the location key, we invoke the following functions:

  • getCurrentConditions(): We invoke it on line 8 to get the current weather conditions of the given location.
  • getHourlyForecasts(): We invoke it on line 37 to get hourly weather forecasts of the given location for the next 12 hours.
  • getDailyForecasts(): We invoke it on line 71 to get the daily weather forecasts of the given location for the next five days.

All the retrieved data then returns to the webpage, where it is displayed in their respective tabs. In case any of the endpoints fail to execute, an appropriate error message is displayed under their respective tabs.