appleLover
appleLover

Reputation: 15691

Python Class __init__ Not Working

This is some really simple code I am using with sqlalchemy and I am missing something basic here about how classes work.

class Game(Base):
    __tablename__ = "games"

    id = Column(Integer, primary_key=True)
    a_name = Column(String)

    def __init__(self, **kwargs):
        for k, v in kwargs.iteritems():
             setattr(self, k, v)
        print 'hi'
        self.away_dictionary =  {'name': self.a_name}

    @hybrid_property
    def stuff(self):
        return self.away_dictionary

The following query works:

session.query(Game).first().a_name

but the following query returns an error:

session.query(Game).first().stuff
'Game' object has no attribute 'away_dictionary'

I also have an even more basic problem, when I query the Game class it doesn't print out 'hi'. So could someone please explain why 'hi' isn't printed out everytime I use a Game instance? And the second question is how can I build and access the away_dictionary I want to have for each instance of this class?

Upvotes: 7

Views: 19056

Answers (4)

appleLover
appleLover

Reputation: 15691

thanks for the comments. is it just me or is sqlalchemy kind of confusing?

anyway, as people have pointed out above the __init__ method apparently is not called when you do a query.

The SQLAlchemy ORM does not call __init__ when recreating objects from database rows. The ORM’s process is somewhat akin to the Python standard library’s pickle module, invoking the low level __new__ method and then quietly restoring attributes directly on the instance rather than calling __init__.

the solution to this is to add the following code:

from sqlalchemy.orm import reconstructor
@reconstructor
awesome_true_init(self):
    self.away_dictionary = {'hi': 'i work!!'}

this function will act like a real __init__ and get called whenever you create the object!!

Upvotes: 2

rmunn
rmunn

Reputation: 36678

Ah ha. I was just about to point out that it's bizarre that stuff isn't getting found, and I would expect away_dictionary not to be found instead... and you edited your post and changed the error message that you're quoting. It is indeed away_dictionary that isn't getting found, because it's normally created in your class's __init__() method and __init__() isn't getting called.

Normally, __init__() would be called when you create an instance, but when you use the class in SQLAlchemy's queries, it's skipping the __init__() method. I suspect this is something to do with how SQLAlchemy's declarative_mapper works, but I'm rusty enough on SQLAlchemy that I don't know off the top of my head how to fix it. If I find out, I'll edit this answer later and tell you.

But for now, you should probably not rely on your __init__() method getting called in your SQLAlchemy model objects (that is, anything derived from Base). See if you can structure your code in some other way.

Upvotes: 1

Bryan
Bryan

Reputation: 1

The reason session.query(Game).first().a_nameworks, but session.query(Game).first().stuff doesn't is a simple syntactic issue. a_name is a variable, an attribute of the class Game, so you refer to it just by typing a_name. stuff, on the other hand, is a method of that class, so you need a pair of parentheses after it, even if, as in this case, there isn't anything inside them. So try using session.query(Game).first().stuff().

"hi" isn't being printed because init is only called when you create an object using that constructor, which query isn't doing.

Upvotes: -2

Frank Ruben
Frank Ruben

Reputation: 105

You're not creating a Game instance in your queries above, you only pass the Game class object. Hence the init() constructor is never called. If you need a Game instance for query, you need this: session.query(Game()).first().stuff.

Upvotes: 1

Related Questions