Hi Michael,
Still stuck, I don't mixin foreign keys or relationships. When is a
Column attached to a table in declarative?
My code is:
import datetime
from datatypes import *
from accessors import member_accessor, reference_accessor
from sqlalchemy import *
from sqlalchemy.orm import relationship
from sqlalchemy.orm.session import sessionmaker
from sqlalchemy.ext.declarative import declared_attr, DeclarativeMeta
from sqlalchemy.types import Text, BigInteger, Float, Boolean, Date,
Time
#---------------------------------------------------------------------------
engine = create_engine('sqlite:///:memory:', echo=False)
Session = sessionmaker(bind=engine)
register = dict()
#---------------------------------------------------------------------------
class BaseBase(object):
session = Session()
@declared_attr
def __tablename__(cls): return cls.__name__
def __init__(self, **kwargs):
Base.__init__(self, **kwargs)
self.session.add(self)
print str(self) + " added to session " + str(self.session)
def __repr__(self):
out = "type: " + type(self).__name__ + "{"
for name, mem in self.__dict__:
out += name + ": " + str(mem) + ", "
out += "}"
return out
#--------------------------------------------------------------------
class AtomBase(BaseBase):
id = Column(Integer, primary_key=True)
atomic = True
#--------------------------------------------------------------------
class atommeta(DeclarativeMeta):
def __new__(mcls, name, coltype):
return DeclarativeMeta.__new__(mcls, name, (AtomBase, Base),
{name:Column(coltype, nullable = False)})
def __init__(cls, name, coltype):
register[name] = cls
return DeclarativeMeta.__init__(cls, name, (AtomBase, Base),
{})
#---------------------------------------------------------------------------
class BaseLink(BaseBase):
member_name = Column(String(64), primary_key = True) #Name of
member of parent class
member_table = Column(String(64), primary_key = True) #Name of
table in which value of member resides
member_id = Column(Integer, primary_key = True) #record
is in member_table, with previous column enables polymorphism
def _getitem(self):
t = register[self.member_table]
return self.session.query(t).filter(self.member_id ==
t.id).one()
def _setitem(self, val):
try: del self.item
except AttributeError: pass
self.member_table = val.__tablename__
self.member_id =
val.id
def _delitem(self):
t = register[self.member_table]
self.session.query(t).filter(
t.id == self.member_id).delete()
item = property(_getitem, _setitem, _delitem)
#---------------------------------------------------------------------------
class BaseTable(BaseBase):
id = Column(Integer, primary_key = True)
created_at = Column(DateTime, default=datetime.datetime.now())
atomic = False
#---------------------------------------------------------------------------
class linkmeta(DeclarativeMeta):
def __new__(mcls, parent):
return DeclarativeMeta.__new__(mcls, "%s_links" %
parent.__name__, (BaseLink, Base),
{"parent_id": Column(Integer,
ForeignKey(
parent.id), primary_key=True)})
def __init__(cls, parent):
return DeclarativeMeta.__init__(cls, "%s_links" %
parent.__name__, (BaseLink, Base), {})
#---------------------------------------------------------------------------
class tablemeta(DeclarativeMeta):
def __new__(mcls, typedef):
out = DeclarativeMeta.__new__(mcls, str(
typedef.name),
(BaseTable,Base), {})
out.links = linkmeta(out) #<== Creates class/table enables
links to other tables
members = typedef.all()
for mem in members:
if not
mem.type.name in register:
tablemeta(mem.type)
setattr(out, "_" +
mem.name, relationship(out.links,
uselist =
(mem.multiplicity != "one"),
backref =
mem.name,
primaryjoin =
and_(out.links.parent_id ==
out.id,
out.links.member_name ==
mem.name)))
return out
def __init__(cls, typedef):
register[cls.__name__] = cls
temp = dict()
members = typedef.all()
for mem in members:
if mem.reference:
temp[
mem.name] = reference_accessor(
mem.name,
register[mem.type_name], mem.multiplicity)
else:
temp[
mem.name] = member_accessor(
mem.name,
register[mem.type_name], mem.multiplicity)
return DeclarativeMeta.__init__(cls,
typedef.name,
(BaseTable,Base), temp)
#---------------------------------------------------------------------------
def createClasses(engine, session):
print "creating classes and tables"
atommeta("text", Text)
atommeta("integer", BigInteger)
atommeta("decimal", Float)
atommeta("boolean", Boolean)
atommeta("date", Date)
atommeta("time", Time)
typedefs = session.query(Type).filter(Type.atomic == False).all()
for typedef in typedefs:
tablemeta(typedef)
print
"-----------------------------------------------------------------------------------"
for reg in register:
print reg
Base.metadata.create_all(engine) #<== ERROR
print"done"
Please help ....
The typedefs variables describe classes and members, and are queried
from normal tables