wuno
wuno

Reputation: 9885

Parsing JSON With Requests In Django

I am making an api call with requests in a django application. I keep getting a key error on name. The json response is pretty large so I am only picking certain fields out to use. But the error is on the very first item in the json list.

The first couple lines of the json looks like this,

"cards": [
    {
      "name": "Air Elemental",
      "manaCost": "{3}{U}{U}",
      "cmc": 5,
      "colors": [
        "Blue"
      ],
      "type": "Creature — Elemental",
      "types": [
        "Creature"
      ],
      "subtypes": [
        "Elemental"
      ],

And in my view I am parsing the json like this,

def graphs(request):
    if request.user.is_authenticated():
        parsedData = []
        req = requests.get('https://api.magicthegathering.io/v1/cards')
        jsonList = []
        jsonList.append(json.loads(req.content.decode()))
        cardData = {}
        for cards in jsonList:
            cardData['name'] = cards['name']
            cardData['manaCost'] = cards['manaCost']
            cardData['colors'] = cards['colors']
            cardData['type'] = cards['type']
            cardData['rarity'] = cards['rarity']
            cardData['set'] = cards['set']
            cardData['text'] = cards['text']
            cardData['flavor'] = cards['flavor']
            cardData['artist'] = cards['artist']
            cardData['power'] = cards['power']
            cardData['toughness'] = cards['toughness']
            cardData['layout'] = cards['layout']
            cardData['multiverseid'] = cards['multiverseid']
            cardData['id'] = cards['id']
        parsedData.append(cardData)
        return render(request, 'graphs/graphs.html', {'data': parsedData})
    else:
        return redirect('index')

The Error

KeyError at /graphs/graphs/
'name'

And in my view I am accessing the data like this,

 {% for key in cards %}
                      <tr>
                          <td>{{ key.name }}</td>
                          <td>{{ key.manaCost }}</td>
                          <td>{{ key.colors }}</td>
                          <td>{{ key.type }}</td>
                          <td>{{ key.rarity }}</td>
                          <td>{{ key.set }}</td>
                          <td>{{ key.text }}</td>
                          <td>{{ key.flavor }}</td>
                          <td>{{ key.artist }}</td>
                          <td>{{ key.power }}</td>
                          <td>{{ key.toughness }}</td>
                          <td>{{ key.layout }}</td>
                          <td>{{ key.multiverseid }}</td>
                          <td>{{ key.id }}</td>
                      </tr>
                  {% endfor %}

Why am I receiving the key error?

Upvotes: 1

Views: 1545

Answers (4)

Alasdair
Alasdair

Reputation: 309089

When you do

json.loads(req.content.decode())

You get a dictionary with one key, cards.

{'cards': [<list of cards>]}

It doesn't make sense to append that to jsonList, because then you have,

[{'cards': [<list of cards>]}

and when you loop through that list, you get the single dictionary that you started with. As we said before, that dictionary has a single key, cards, so you get the key error when you try to access the name key that doesn't exist.

You really want to loop through [<list of cards>], so set jsonList to that list instead.

    req = requests.get('https://api.magicthegathering.io/v1/cards')
    jsonData = json.loads(req.content.decode())
    jsonList = jsonData['cards']
    for cards in jsonList:
        cardData = {}  # move this line inside the loop
        cardData['name'] = cards['name']
        ...
        # make sure this line is inside the loop so that you append
        # every card to parsedData
        parsedData.append(cardData) 

As mentioned in the comments and other answers, you could use the request's json() method to simplify your code:

    req = requests.get('https://api.magicthegathering.io/v1/cards')
    jsonList = req.json()['cards']
    for cards in jsonList:
        ...

Upvotes: 3

Jonathan Windridge
Jonathan Windridge

Reputation: 407

If you read the documentation for requests here, jsonList = req.json() will assign a dictionary / list of dicts corresponding to the JSON you receive from the external API resource (and is probably more readable than calling json.loads(...).

I would suspect that the KeyError you are receiving is being thrown at your line cardData['name'] = cards['name'] because the JSON decoding process isn't working as you expect.

Failing that, have you checked that you're iterating through the correct template variable (for key in data) since that seems to be what you're passing through to the template.

Upvotes: 1

laike9m
laike9m

Reputation: 19388

Wait, your json is

"cards": [
    {"name": "Air Elemental",...}
]

Then you load it like this

jsonList = []
jsonList.append(json.loads(req.content.decode()))

Doesn't it make jsonList

[
    {"cards": [{"name": "Air Elemental",...}]}
]

When you iterate over it, you'll get {"cards": [{"name": "Air Elemental",...}]}, and apparently it doesn't have key name. You need to iterate over jsonList['cards'].

Upvotes: 2

Snuggert
Snuggert

Reputation: 175

Because the key name cannot be found in the cards dict.

To debug this, you should probably do a print of each cards dict and see what dict is irregular.

Good luck!

Upvotes: 2

Related Questions