On Jan 30, 2012, at 9:49 AM, Martijn Moeling wrote: > sorry I have to get back on this. I renamed all Columns in my application > definitions to MyColumn a while back. and everything worked. > Now that I'm starting to use functionality of MyColumn. (The reason I needed > this) I run into some trouble.
so we can skip the easy "_constructor" thing and implement the rest of Column. If you read the first error message you get with a straight subclass: TypeError: Could not create a copy of this <class '__main__.MySpecialColumn'> object. Ensure the class includes a _constructor() attribute or method which accepts the standard Column constructor arguments, or references the Column class itself. Original error: __init__() takes exactly 2 arguments (8 given) So Column goes through a lot of trouble to try to diagnose what's going on. It's telling us to create a method called _constructor(), that accepts the standard arguments that Column does. The return value is our modified column: class MySpecialColumn(Column): x = 0 y = 0 def __init__(self, type_, **options): filtered_options = {} for name, option in options.items(): if hasattr(self, name): setattr(self, name, option) else: filtered_options[name] = option Column.__init__(self, type_, **filtered_options) def _constructor(self, name, type_, **kw): kw['x'] = self.x kw['y'] = self.y col = MySpecialColumn(type_, **kw) col.name = name return col > > At the other end, I might need to introspect the objects, I have tried but I > have trouble in relating to X or Y since the Name Column is an > InstrumentedAttribute. Yeah to get at them directly you'd need to say: assert MyClass.value.property.columns[0].x == 5 if you want MyClass.value.x == 5, you need to tack that on when it gets instrumented: @event.listens_for(Base, 'attribute_instrument') def configure_listener(class_, key, inst): if isinstance(inst.property, ColumnProperty) and \ isinstance(inst.property.columns[0], MySpecialColumn): inst.x = inst.property.columns[0].x inst.y = inst.property.columns[0].y > > > One other thing. I can get Columns by iterating over self.__table__.Columns. > I can get Foreign keys using: > inspector.get_foreign_keys(SomeClass.__tablename__) I'd note those are not at all equivalent operations, in that inspector is going to go out to the database in order to get the FK information. Assuming your table metadata has it configured, you can get it locally by iterating through SomeClass.__table__.foreign_keys: for fk in MyClass.__table__.foreign_keys: print fk.parent, fk.column if you want the full constraint object, which I'd recommend if you have composite FKs in use: for const in MyClass.__table__.constraints: if isinstance(const, ForeignKeyConstraint): for element in const.elements: print element.parent, element.column > > But Now I need to access the relation objects defined in my classes and > Introspect them. relationship is not the same as a foreign key, see below... There's a ticket for 0.8 that would attempt to provide more accessors for these things, including things like mapper.relationships and stuff like that. Feel free to add in things we should consider on http://www.sqlalchemy.org/trac/ticket/2208. an example with everything happening, including in a tricky from_self() query: from sqlalchemy import create_engine, Column, Integer, ForeignKey, ForeignKeyConstraint from sqlalchemy.orm import Session, configure_mappers, relationship from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import event from sqlalchemy.orm.properties import ColumnProperty, RelationshipProperty class MySpecialColumn(Column): x = 0 y = 0 def __init__(self, type_, **options): filtered_options = {} for name, option in options.items(): if hasattr(self, name): setattr(self, name, option) else: filtered_options[name] = option Column.__init__(self, type_, **filtered_options) def _constructor(self, name, type_, **kw): kw['x'] = self.x kw['y'] = self.y col = MySpecialColumn(type_, **kw) col.name = name return col Base= declarative_base() @event.listens_for(Base, 'attribute_instrument') def configure_listener(class_, key, inst): if isinstance(inst.property, ColumnProperty) and \ isinstance(inst.property.columns[0], MySpecialColumn): inst.x = inst.property.columns[0].x inst.y = inst.property.columns[0].y class MyClass(Base): __tablename__ = "sometable" id = Column(Integer, primary_key=True) foo_id = Column(Integer, ForeignKey('foo.id')) value = MySpecialColumn(Integer, nullable=False, x=5, y=12) myfoo = relationship("MyFoo") class MyFoo(Base): __tablename__ = 'foo' id = Column(Integer, primary_key=True) assert MyClass.value.property.columns[0].x == 5 # configure mappers now to fire off # the instrumentation event ahead # of time, just so we can see value.x configure_mappers() assert MyClass.value.x == 5 # foreign keys for fk in MyClass.__table__.foreign_keys: print fk.parent, fk.column for const in MyClass.__table__.constraints: if isinstance(const, ForeignKeyConstraint): for element in const.elements: print element.parent, element.column # relationships for prop in MyClass.__mapper__.iterate_properties: if isinstance(prop, RelationshipProperty): print "relationship:", prop.key, prop.mapper.class_, e = create_engine("sqlite://", echo=True) Base.metadata.create_all(e) s = Session(e) s.add_all([ MyClass(value=12), MyClass(value=18) ]) s.commit() # from_self() here creates a subquery and exercises the # column copying print s.query(MyClass).filter( MyClass.value.between(MyClass.value.x, MyClass.value.y) ).from_self().all() -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalchemy@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.