'TypeError: string indices must be integers, why?

I get

TypeError: string indices must be integers

with this code:

from xml.etree import cElementTree as ET
from collections import defaultdict
def etree_to_dict(t):
d = {t.tag: {} if t.attrib else None}
children = list(t)
if children:
  dd = defaultdict(list)
  for dc in map(etree_to_dict, children):
    for k, v in dc.items():
      dd[k].append(v)
      d = {t.tag: {k: v[0] if len(v) == 1 else v for k, v in dd.items()}}
      if t.attrib:
        d[t.tag].update(('@' + k, v) for k, v in t.attrib.items())
      if t.text:
        text = t.text.strip()
        if children or t.attrib:
          if text:
            d[t.tag]['#text'] = text
          else:
            d[t.tag] = text
          return d

I think the problem is here:

e = ET.parse('adversolutions.xml')
d = etree_to_dict(e.getroot())
products = d['yml_catalog']['shop5']

for p in products:
  product = Product()
  product.name = p['name']
  product.description = p['description']
  product.price = p['price']
  product.category = p['category']
  product.external_url = p['url']
  product.category_id = p['categoryId']
  product.currencies = p['currencies']

  product.save()

How can I fix this bug?

All this is to deserialize XML and save the data and model in Django.

All of the traceback:

Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/alexandr/beo/lib/python3.4/site-packages/django/core/management/__init__.py", line 385, in execute_from_command_line
    utility.execute()
  File "/home/alexandr/beo/lib/python3.4/site-packages/django/core/management/__init__.py", line 354, in execute
    django.setup()
  File "/home/alexandr/beo/lib/python3.4/site-packages/django/__init__.py", line 21, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/home/alexandr/beo/lib/python3.4/site-packages/django/apps/registry.py", line 108, in populate
    app_config.import_models(all_models)
  File "/home/alexandr/beo/lib/python3.4/site-packages/django/apps/config.py", line 202, in import_models
    self.models_module = import_module(models_module_name)
  File "/home/alexandr/beo/lib/python3.4/importlib/__init__.py", line 109, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 2254, in _gcd_import
  File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
  File "<frozen importlib._bootstrap>", line 2226, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1200, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 1129, in _exec
  File "<frozen importlib._bootstrap>", line 1471, in exec_module
  File "<frozen importlib._bootstrap>", line 321, in _call_with_frames_removed
  File "/home/alexandr/beo/posts/models.py", line 9, in <module>
    from products.models import Product
  File "/home/alexandr/beo/products/models.py", line 155, in <module>
    product.name = p['name']
TypeError: string indices must be integers

With this line, all works:

products = d['yml_catalog']['shop5']

The problems start here:

for p in products:
  product = Product()
  product.name = p['name']
  product.description = p['description']
  product.price = p['price']
  product.category = p['category']
  product.external_url = p['url']
  product.category_id = p['categoryId']
  product.currencies = p['currencies']

  product.save()

print(products):

Piece of the large XML file:

'@available': 'true', 'param': {'@name': 'Размер', '@unit': 'INT', '#text': 'L'}, '@id': '117213', 'name': 'Штаны Pocket Grey', 'oldprice': '1990', '@group_id': '1172', 'description': None, 'picture': 'http:///upload/iblock/559/559b4fe1c3b397bf84eb16686bd5aadf.jpg', 'url': 'http:///catalog/shtany/galife_pocket_grey/', 'currencyId': 'RUB', 'price': '1990'}, {'vendor': 'Envy Lab', '@available': 'true', 'param': {'@name': 'Размер', '@unit': 'INT', '#text': 'S'}, '@id': '117511', 'name': 'Галифе Dark Black', 'oldprice': '1990', '@group_id': '1175', 'description': None, 'picture': 'http:///upload/iblock/11d/11d1c223f4e65b347cd5823fff9e5e9b.jpg', 'url': 'http:///catalog/shtany/galife_dark_black/', 'currencyId': 'RUB', 'price': '1990'}, {'vendor': 'Envy Lab', '@available': 'true', 'param': {'@name': 'Размер', '@unit': 'INT', '#text': 'M'}, '@id': '117512', 'name': 'Галифе Dark Black', 'oldprice': '1990', '@group_id': '1175', 'description': None, 'picture': 'http:///upload/iblock/11d/11d1c223f4e65b347cd5823fff9e5e9b.jpg', 'url': 'http:///catalog/shtany/galife_dark_black/', 'currencyId': 'RUB', 'price': '1990'}, {'vendor': 'Envy Lab', '@available': 'true', 'param': {'@name': 'Размер', '@unit': 'INT', '#text': 'L'}, '@id': '117513', 'name': 'Галифе Dark Black', 'oldprice': '1990', '@group_id': '1175', 'description': None, 'picture': 'http:///upload/iblock/11d/11d1c223f4e65b347cd5823fff9e5e9b.jpg', 'url': 'http:///catalog/shtany/galife_dark_black/', 'currencyId': 'RUB', 'price': '1990'}]}, 'url': 'http://www.envylab.ru', 'name': 'Envylab', 'categories': {'category': [{'#text': 'Поло', '@id': '61'}, {'#text': 'Толстовки', '@id': '65'}, {'#text': 'Штаны', '@id': '72'}, {'#text': 'Шапки', '@id': '74'}, {'#text': 'Рубашки', '@id': '76'}]}, 'company': 'Envylab'}

print(p):

One of the results:

categories

print(type(products))

<class 'dict'>


Solution 1:[1]

You have a traceback that says

product.name = p['name']
TypeError: string indices must be integers

which means that apparently p is a string, while you're trying to use it like a dictionary.

You're right that the issue appears around here (although it probably comes from a problem before you get there):

products = d['yml_catalog']['shop5']

# Please add this print
print(products)
print(type(products))

for p in products:
    # Please add this print
    print(p)
    product = Product()
    product.name = p['name']
...

Apparently, you expect products to be a list of dictionaries, but you get a list of strings.

It should be easy to verify by printing products before the loop and/or p at the beginning of the loop.

print is a great and simple debug tool, well suited for these kind of issues.

It is unclear what products is. You may also print its type (see edited code above).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Peter Mortensen