views:

30

answers:

2

Hi,

I'm getting myself into issues with python class attributes vs data attributes in my sqlalchemy model. This is a small example to demonstrate what's happening:

# -*- coding: utf-8 -*-
import cherrypy
import sqlalchemy
from sqlalchemy import create_engine
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('mysql://USER:PASS@localhost/SCHEMA?charset=utf8', echo=True)
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base()

class User(Base):
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    username = Column(String, nullable=False)
    name = Column(String, nullable=False)
    email = Column(String, nullable=False)

    def __init__(self, username, name, email):
        self.username = username
        self.name = name
        self.email = email
        self.data_attribute = "my data attribute"
        print "__init__"

    def __repr__(self):
        print "__repr__"
        return "<User('%s','%s', '%s')>" % (self.username, self.name, self.email)

class Root(object):

    @cherrypy.expose
    def test(self):        
        our_user = session.query(User).one()        
        return our_user.data_attribute #error

if __name__ == '__main__':

    cherrypy.tree.mount(Root())
    cherrypy.server.quickstart()
    cherrypy.engine.start()

That code errors because when the objects are taken from the DB __init__ doesn't run so data_attribute doesn't exist. If I put data_attribute in with the Column objects is becomes a class attribute (I think) and therefore carries the same value for all instances of User. This is not what I want.

What do I need to do to have a data attribute on my User object that doesn't come from the DB but also is unique for each instance of User?

Edit: I should probably point out that data_attribute will not always just be a simple string set in __init__ - this is just to demonstrate the problem.

A: 

You should be using super() to call the base class constructor:

def __init__(self, username, name, email, *args, **kwargs ):
    super( User, self ).__init__( *args, **kwargs ) # Python 2.x or 3.x
    #super().__init__( *args, **kwargs ) # Python 3.x only
    self.username = username
    ...
robert
according to my print statement `User.__init__` never runs so how can I make a call to the base? is there some python magic I'm missing here??
OrganicPanda
I misread part of the question, so I guess this doesn't directly apply.
robert
+1  A: 

SQLAlchemy provides special syntax for such cases, http://www.sqlalchemy.org/docs/mappers.html#constructors-and-object-initialization

Daniel Kluev
legend. thank you very much
OrganicPanda