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?
asked Jun 23, 2013 at 0:22
appleLoverappleLover
13.8k8 gold badges32 silver badges50 bronze badges
6
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
.
answered Jun 23, 2013 at 0:42
4
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.
answered Jun 23, 2013 at 1:41
rmunnrmunn
33k9 gold badges70 silver badges103 bronze badges
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!!
answered Jun 23, 2013 at 3:40
appleLoverappleLover
13.8k8 gold badges32 silver badges50 bronze badges
2
The reason session.query[Game].first[].a_name
works, 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.
answered Jun 23, 2013 at 0:47
1