views:

198

answers:

2

I've been trying to map an object to a database using SQLAlchemy but have run into a snag.

Edit: Basically changed a whole bunch of stuff.

Version info if handy: [OS: Mac OSX 10.5.8 | Python: 2.6.4 | SQLAlchemy: 0.5.8]

The class I'm going to map:

class Student(object):
    def __init__(self, id, name):
        self.id = id
        self.name = name

    def __repr__(self):
        return str(self)

    def __str__(self):
        return "%s %s" %(self.id, self.name)

Background:

Now, I've got a function that reads in the necessary information from a text database into these objects. The function more or less works and I can easily access the information from the objects.

Before the SQLAlchemy code runs, the function will read in the necessary info and store it into the Class. There is a dictionary called students which stores this as such:

students = {}
students[id] = Student(<all the info from the various "reader" functions>)

Afterwards, there is an "allocation" algorithm that will allocate projects to student. It does that well enough. The allocated_project remains as None if a student is unsuccessful in getting a project.

SQLAlchemy bit:

So after all this happens, I'd like to map my object to a database table.

from sqlalchemy import *
from sqlalchemy.orm import *

engine = create_engine('sqlite:///:memory:', echo=False)
metadata = MetaData()
students_table = Table('studs', metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String)
)
metadata.create_all(engine)
mapper(Student, students_table)

Now after that, I was curious to see if I could print out all the students from my students dictionary.

for student in students.itervalues():
    print student

What do I get but an error. This error only takes place if try to print as I am, after calling the mapper:

Traceback (most recent call last):
  File "~/FYP_Tests/FYP_Tests.py", line 140, in <module>
    print student
  File "~/FYP_Tests/Parties.py", line 30, in __str__
    return "%s %s" %(self.id, self.name)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/SQLAlchemy-0.5.8-py2.6.egg/sqlalchemy/orm/attributes.py", line 158, in __get__
  return self.impl.get(instance_state(instance), instance_dict(instance))
AttributeError: 'NoneType' object has no attribute 'get'

I'm at a loss as to how to resolve this issue, if it is an issue. If more information is required, please ask and I will provide it.

Questions:
  1. Does the SQLAlchemy mapper change anything about the original Class/dictionary?
  2. Does this have anything specific to way the get works with dictionaries?
A: 

It looks like you might have a name shadowing conflict where Column('id'...) hides Student.id. Changing Student.__init__.id to Student._init__.sid would be a quick test to confirm or refute this conjecture.

There is mention of this connection in the third code block of the SQLAlchemy tutorial on mappings.

For example, replacing your first code snippet with this fragement:

class Student(object):
    def __init__(self, name, id):
        self.sid = id
        self.name = name
        # and so on

Obviously other references to Student.id would have to change as well.

msw
@msw: Will try and let you know.
Az
I added the "quick test" sentence to (hopefully) clarify
msw
@msw: Ah, no luck. Pretty much the same error message.
Az
@msw: Just double-checking, what in essence does 'self.sid = id' do? Isn't it usually 'self.something = something'? (Do note, I'm a Python beginner) EDIT: Tried that. Code still works, but the error message hasn't changed. Does it have anything to do with the existence of the `allocated_project` being `None`?
Az
The (extremely powerful, yet somewhat mystical) semantics of `__getattr__` still have me befuddled. Good luck. +1 for a well presented question.
msw
`self.id = id` is proper idiom, since I guessed that the `Column('id'` was hiding `self.id` I suggested a quick-and-dirty check. The only meaning of `sid` was that it wasn't `id`, it could have been `fred` just as well to test my guess.
msw
As I'm just at beginner+epsilon level, I'd start reading `sqlalchemy/orm/attributes.py` at this point, but I'm not responsible if your head explodes o_O
msw
@msw: I appreciate the help.
Az
+1  A: 

You are creating Student instances before mapping class which modifies class to SQLAlchemy needs. So your instance is not properly initialized. Just put the lines creating Student instances after calling mapper(Student, students_table) and everything will work as expected.

Denis Otkidach
I think you've nailed it. When I try this sort of fancy `for students in students.itervalues: session.add(student)` I get an error that says something about creating an instance before mapping. So, basically, this bit of database code should sit before I start reading in the information from the text files?
Az
@Denis Otkidach: Thankyouthankyouthankyouthankyouthankyou!
Az