0

My Flask-Restful Web-server has a list of dicts called mashrecipies.

mashrecipies = [
    {
        'id': 1,
        'name': 'Kölsch',
        'description': 'Top fermented ale from Köln'

    },
    {
        'id': 2,
        'name': 'IPA',
        'description': 'Classic British Imperial Pale Ale'
    },
]

I can successfully update the dicts from a web-client via Http PUT service.

I can also fill the list mashrecipies with records from a SQLite DB using SQLAlchemy ORM via a class Mash.

Base = declarative_base()

class Mash(Base):
    __tablename__ = 'mash'

    id = Column(Integer, primary_key=True)
    selected = Column(Boolean)
    name = Column(String)
    type = Column(String)
    description = Column(String)

    def __repr__(self):
        return '<{id}, {selected}, {name}, {type}, {desc}>'\
            .format(id=self.id, selected=self.selected, name=self.name, type=self.type, desc=self.description)
class Db():
    engine = create_engine(SQLALCHEMY_DATABASE_URI)
    Session = sessionmaker(bind=engine)
    session = Session()

def get_mashrecipies(self,):
    mashrecipies.clear()
    rec = None
    for rec in self.session.query(Mash).order_by(Mash.id):
        mashrecipies.append(rec)

However if I have filled the list using SQLAlchemy, and then try to update the list contents via the same Http PUT I now get the error:

File "/Users/xxx/PycharmProjects/AleSheep/server/apis/mashrecipesapi.py", line 81, in mashrecipe = [mashrecipe for mashrecipe in mashrecipies if mashrecipe['id'] == id] TypeError: 'Mash' object is not subscriptable

The put handler in my Flask-Restful Resource is:

def put(self, id):
    mashrecipe = [mashrecipe for mashrecipe in mashrecipies if mashrecipe['id'] == id]

The only explicit link (in my code) between mashrecipies and Mash is when I fill mashrecipies from Mash by directly appending records from the SQLAlchemy query.

If rather than doing mashrecipies.append(rec), I copy the fields into a dict, and append the dict:

dict = {'id': rec.id, 'name': rec.name, 'description': rec.description}
mashrecipies.append(dict)

then my PUT service works without error again. This solves my immediate problem.

But what is the difference between filling the list with dicts with fields copied from a SQLAlchemy query (OK), and directly appending records returned from a query (NOT OK)?

Is SQLAlchemy tracking changes to the query records, perhaps to persist them?

FlyingSheep
  • 804
  • 1
  • 9
  • 20

1 Answers1

1

Based on the error text, I believe that the type of object you store in mashrecipe (of type Mash) is not subscriptable. That is, it does not have the function that python interpreter calls when you use [] on an instance. For example, arrays and lists are subscriptable and do have this function.

To make an object subscriptable you have to implement function __getitem__(self, index). It will be called when you use (for example) mashrecipe["hello"]. The first argument (self) is an instance of an object and the second (index) is the index you are trying to access. The function should return whatever you are expecting.

That seems like this functionality is not implemented in a class you are inheriting from and it is not implemented in your class. Thus, the error.

Read more about __getitem__ here - http://www.diveintopython.net/object_oriented_framework/special_class_methods.html

Dmitry Torba
  • 3,004
  • 1
  • 14
  • 24
  • Super Dimitry! I had not clicked that the list was storing instances of Mash, which is obvious now you point it out! If I change `[...mashrecipe[id] == id]` to `[...mashrecipe.id == id]`, then the error no longer occurs, and there is no need to add the `__getitem__` function to the `Mash` class. – FlyingSheep Aug 18 '16 at 18:02
  • ..and before anyone else does, I will link this [SO question explaining the object types that are subscriptable](http://stackoverflow.com/questions/216972/in-python-what-does-it-mean-if-an-object-is-subscriptable-or-not) – FlyingSheep Aug 18 '16 at 18:20