0

I try to make API requests to fetch data from a third party API to manipulate/render the data into my dashboard. Including the responsed data everything runs well so far, but it seems something is wrong with the dictionary/keys within the json api data.

In particular I would like to grab the values of the keys 'name' and 'country' which are correctly fetched via the http response according to the Django debug.

I always end up with a KeyError as shown below.

What do I miss here? (I am not sure if this is important, but my linter tells me that json is imported but unused within the views.py)

This is the response:

Variable    Value
request 
<WSGIRequest: GET '/dashboard/'>
response    
<Response [200]>
team_data   
{'api': {'ENDOINTS': {'countries': {'countries': 'https://www.api-football.com/demo/api/v2/countries'},
                      'events': {'events': 'https://www.api-football.com/demo/api/v2/events/{fixture_id}'},
                      'fixtures': {'date': 'https://www.api-football.com/demo/api/v2/fixtures/date/{date}',
                                   'h2h': 'https://www.api-football.com/demo/api/v2/fixtures/h2h/{team_1}/{team_2}',
                                   'id': 'https://www.api-football.com/demo/api/v2/fixtures/id/{fixture_id}',
                                   'league': 'https://www.api-football.com/demo/api/v2/fixtures/league/{league_id}',
                                   'live': 'https://www.api-football.com/demo/api/v2/fixtures/live',
                                   'team': 'https://www.api-football.com/demo/api/v2/fixtures/team/{team_id}'},
                      'leagues': {'country': 'https://www.api-football.com/demo/api/v2/leagues/country/{country_name}/{season}',
                                  'league': 'https://www.api-football.com/demo/api/v2/leagues/league/{league_id}',
                                  'leagues': 'https://www.api-football.com/demo/api/v2/leagues',
                                  'season': 'https://www.api-football.com/demo/api/v2/leagues/season/{season}'},
                      'lineups': {'lineups': 'https://www.api-football.com/demo/api/v2/lineups/{fixture_id}'},
                      'odds': {'bookmakers': 'https://www.api-football.com/demo/api/v2/odds/bookmakers/',
                               'fixture': 'https://www.api-football.com/demo/api/v2/odds/fixture/{fixture_id}',
                               'labels': 'https://www.api-football.com/demo/api/v2/odds/labels/',
                               'league': 'https://www.api-football.com/demo/api/v2/odds/league/{league_id}'},
                      'players': {'player': 'https://www.api-football.com/demo/api/v2/players/player/{player_id}',
                                  'seasons': 'https://www.api-football.com/demo/api/v2/players/seasons',
                                  'team': 'https://www.api-football.com/demo/api/v2/players/team/{team_id}'},
                      'seasons': {'seasons': 'https://www.api-football.com/demo/api/v2/seasons'},
                      'standings': {'leagueTable': 'https://www.api-football.com/demo/api/v2/leagueTable/{league_id}'},
                      'statistics': {'fixture': 'https://www.api-football.com/demo/api/v2/statistics/fixture/{fixture_id}',
                                     'team': 'https://www.api-football.com/demo/api/v2/statistics/{league_id}/{team_id}'},
                      'teams': {'league': 'https://www.api-football.com/demo/api/v2/teams/league/{league_id}',
                                'team': 'https://www.api-football.com/demo/api/v2/teams/team/{team_id}'},
                      'transfers': {'player': 'https://www.api-football.com/demo/api/v2/transfers/player/{player_id}',
                                    'team': 'https://www.api-football.com/demo/api/v2/transfers/team/{team_id}'}},
         'WARNING': 'THIS IS A DEMO AND DOES NOT REPRESENT THE ENTIRE API. THE '
                    'DATA IS LIMITED AND NOT UP TO DATE AND SERVES ONLY AS AN '
                    'EXAMPLE. FOR PRODUCTION ENVIRONEMENT USE : '
                    'HTTPS://API-FOOTBALL-V1.P.RAPIDAPI.COM/V2/',
         'results': 1,
         'teams': [{'code': None,
                    'country': 'Brazil',
                    'founded': 1909,
                    'logo': 'Not available in Demo',
                    'name': 'Internacional',
                    'team_id': 33,
                    'venue_address': 'Avenida Padre Cacique 891, Bairro Menino '
                                     'Deus',
                    'venue_capacity': 50128,
                    'venue_city': 'Porto Alegre, Rio Grande do Sul',
                    'venue_name': 'Estádio José Pinheiro Borda',
                    'venue_surface': 'grass'}]}}

This is my views function:

import requests
from django.shortcuts import render
import json

def team_update(request):
    response = requests.get('http://www.api-football.com/demo/api/v2/teams/team/33')
    team_data = response.json()
    print(team_data)
    return render(request, 'index.html', {
        'name': team_data['name'],
        'country': team_data['country'],
    })

This is the error:

KeyError at /dashboard/
'name'
Request Method: GET
Request URL:    http://127.0.0.1:8000/dashboard/
Django Version: 2.2.5
Exception Type: KeyError
Exception Value:    
'name'
Exception Location: C:\Users\Jonas \Desktop\dasocc\dasocc_site\dasocc_app\views.py in team_update, line 25

Thank you very much for your input in advance.

-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-

Update/Solution:

def team_update(request):
    response = requests.get('http://www.api-football.com/demo/api/v2/teams/team/33')
    team_data = response.json()
    teams = team_data.get('api', {}).get('teams', [])
    if teams and len(teams) == 1:
        teams = teams[0]
        context = {'name': teams['name'], 'country': teams['country']}
    return render(request, 'index.html', {
        'name': teams['name'],
        'country': teams['country'],
    })
5
  • 1
    team_data has the keys WARNING, results and teams so why do you think team_data['name'] should work? Commented Oct 1, 2019 at 15:38
  • uhm good hint, thanks. I just tried it with teams key and get the same error though. Commented Oct 1, 2019 at 15:42
  • 2
    As far as I can see when trying the api myself, the top-level key is api. Look at the output of print(team_data), it's not what you pasted here. Commented Oct 1, 2019 at 15:43
  • Ah right. I missed the top part of the response. So I have to handle a nested key structure, that being said I have to use another approach to grab the required data out of the dic? << I will update the top post with the correct response. Commented Oct 1, 2019 at 15:48
  • No, this is just a regular python dict with nested objects, just access them as you would with any nested python dict. The only thing is teams is a list, so you might want to check that it contains one item before accessing it via [0]. Commented Oct 1, 2019 at 15:53

1 Answer 1

1

The way to safely access your team from such a response is to make sure all the way that you don't access keys that might not exist or objects in a list that might not exist. So don't access keys using [key] but use get(). If the api returns {'status': 'error', 'errors': {...}} then your code would still crash if you just assume it has a key "api":

teams = team_data.get('api', {}).get('teams', [])
if isinstance(teams, list) and len(teams) == 1:
   team = teams[0]
   context = {'name': team['name'], 'country': team['country']} # might also crash if for some reason the api returns a team without country, but not likely
else:
   # handle the issue teams is empty or there's more than 1 team or teams isn't what was expected
Sign up to request clarification or add additional context in comments.

3 Comments

Working! I will post the working example into my initial post. Could you maybe tell me what this means using average joe words? ;p if teams and len(teams) == 1: team = teams[0] Thanks
that's just checking that the teams list isn't empty and contains exactly one team. If that's the case, we access the first element in the list.
Actually we can skip if teams since we always assign the empty list. But we might want to make sure it is a list. I've changed it above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.