0

I've been self-teaching myself programming for less than a month. I'm trying to build a Django site to help the process. I've spent the last 3 days searching for a solution to this problem to no avail.

I stole this code from someone on Github, and it works fine when calling the JSON URL file for which it was specifically written. But I've been trying to modify it to work with another JSON URL file and it's not working. It's a command file that is used to import data into the database. So here's what happens when I run the command:

PS C:\django-1.5.1\dota\mysite> python manage.py update_items
Fetching item list..
TypeError: string indices must be integers

I apologize if there is too much code below, I really don't know what kinds of things people would already implicitly know. I'm trying to import the fields from each game item listed in this JSON file. I'm just starting with 2 fields to try to get this working.

You can view the JSON file from the URL below, but it is formatted like this:

{
"itemdata": {
    "blink": {
        "id": 1,
        "img": "blink_lg.png",
        "dname": "Blink Dagger",
        "qual": "component",
        "cost": 2150,
        "desc": "Active: Blink - Teleport to a target point up to 1200 units away.  If damage is taken from an enemy hero, Blink Dagger cannot be used for 3 seconds.",
        "attrib": "",
        "mc": 75,
        "cd": 12,
        "lore": "The fabled dagger used by the fastest assassin ever to walk the lands.",
        "components": null,
        "created": false
    },
    "blades_of_attack": {
        "id": 2,

And here are the 4 files related to the command file update_items.py:

models.py -- this model defines the database fields

from django.db import models

class Item(models.Model):
    unique_id = models.IntegerField(unique=True)
    dname = models.CharField(max_length=255)

    def __unicode__(self):
        return self.dname

update_items.py -- this is the command file to import the json data into the database

from django.core.management.base import BaseCommand, CommandError
from django.core.management.base import NoArgsCommand
from items.utils.api import SteamWrapper
from items.models import Item

class Command(NoArgsCommand):
help = 'Fetches and updates the items'

def update_item(self, item):
    try:
        db_item = Item.objects.get(unique_id=item['id'])
        print 'Updating %s..' % item['dname']
    except Item.DoesNotExist:
        print 'Creating %s..' % item['dname']
    db_item = Item()
    db_item.unique_id = item['id']
    db_item.dname = item['dname']
    db_item.save()
    print 'Done.'

def fetch_items(self, result):
        try:
            for item in result['itemdata']:
            self.update_item(item)
        except KeyError:
            print "Error while contacting steam API. Please retry."

def handle(self, *args, **options):
      self.stdout.write('Fetching item list..')
      result = SteamWrapper.get_item_list()
      self.fetch_items(result)
      self.stdout.write('Finished.')

api.py -- this is the web api call function thing

import requests
from mysite import settings_local

class   SteamWrapper():
    ''' Steam API wrapper '''

API_KEY = settings_local.STEAM_API_KEY

@classmethod
def _item_send_request(cls, endpoint, *args, **kwargs):
    params = {'key': cls.API_KEY}
    params.update(kwargs)
    request = requests.get(endpoint, params=params)
    return request.json()

@classmethod
def get_item_list(cls):
    return cls._item_send_request(settings_local.DOTA2_ITEM_LIST_ENDPOINT)

local-settings.py

DOTA2_ITEM_LIST_ENDPOINT = 'http://www.dota2.com/jsfeed/itemdata'

So any ideas? Thanks so much...

2
  • Could you print the value of result before for item in result['itemdata'] ? Commented Aug 25, 2013 at 17:23
  • Yes it prints out what I think are unicode strings, like this: {u'itemdata': {u'demon_edge': {u'mc': False, u'img': u'demon_edge_lg.png',... etc. Commented Aug 25, 2013 at 17:37

2 Answers 2

1

The problem is here:

for item in result['itemdata']

itemdata is a dict (of dicts). In Python, iterating through a dict yields the keys: so item there is "blink", "blades_of_attack", and so on, hence the error.

You don't seem to want the keys at all, so you should iterate through result['itemdata'].values().

(Note there is an indentation error in update_item: the line db_item = Item() should be indented within the except, otherwise a new item will always be created.)

Sign up to request clarification or add additional context in comments.

2 Comments

Wow thank you so much! So if I wanted the keys also (blink, blades_of_attack, etc.), the "result['itemdata']:" is already iterating through the keys only, so I can assign those keys to a field in the database with the way I had it, is that correct?
If you just needed the keys, yes. If you need both, you can use items(), which gives tuples of (key, value).
0
def handle(self, *args, **options):
      self.stdout.write('Fetching item list..')
      result = SteamWrapper.get_item_list
      self.fetch_items(result)
      self.stdout.write('Finished.')

The line result = SteamWrapper.get_item_list makes result point at a method of SteamWrapper named get_item_list. Perhaps you've meant to call it by typing SteamWrapper.get_item_list()?

1 Comment

Oh yes, you're right. And now I get this error: TypeError: string indices must be integers! And I actually had this error earlier, which was the original error. Maybe I should update the original post to reflect this error? Thanks for the help!

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.