Looks good, just one curiosity, is there a reason for using "after_parent_attach" event instead of directly using _set_parent to register the LazyForeignKey for being resolved?
2014/1/13 Michael Bayer <[email protected]> > > On Jan 13, 2014, at 1:19 PM, Alessandro Molina < > [email protected]> wrote: > > Just noticed that SQLAlchemy 0.9 broke a LazyForeignKey class that was > provided by TurboGears tgext.pluggable to make possible to declare foreign > keys to models not yet defined at the time the ForeignKey was declared. > > The main use was something like: > > class User(DeclarativeBase): > __tablename__ = 'users' > > registration_id = Column(Integer, LazyForeignKey(lambda: > app_model.Registration.uid)) > > where app_model.Registration was available only at runtime and not when > User class was declared. > Also app_model.Registration table name was not known (as it dynamically > generated to avoid collision between tables of multiple apps plugged at > runtime), so it was not possible to declare the foreign key as a string > with the "tablename.column_name" syntax. > > LazyForeignKey was simply implemented as a subclass of ForeignKey which > provided a custom _colspec property which would resolve the given function > whenever it was first accessed: > https://github.com/TurboGears/tgext.pluggable/blob/master/tgext/pluggable/sqla/relations.py#L4 > > > This approach doesn't work anymore in SQLA 0.9 as _colspec gets accessed > by the ForeignKey constructor itself, calling the lambda at Column > declaration time. > > It seems to me that adapting the LazyForeignKey class to SQLA 0.9 would > require messing a lot more with SQLAlchemy internal code, which is > something I would like to avoid. > > What would be the suggested way to achieve the same feature on SQLA 0.9? > > > Well if the table name were known, then you wouldn’t need such a feature > in the first place as you can just put a string name in ForeignKey(). > > However, as this seems to be a case where a table + declared class is to > eventually refer to some other Table whose name is not known yet, the > ForeignKey() should not exist on the Column at all until that other Table > is available. A simple call to > User.__table__.append_constraint(ForeignKeyConstraint(<now you know what to > put here>)) at the time this information is known would be the cleanest. > > to get at this you’d need to use events. First a way to make an XYZ() > object that can be placed inside of Column and know about it: > > > from sqlalchemy.schema import SchemaItem > from sqlalchemy import event > > class MyThing(SchemaItem): > def _set_parent(self, parent): > pass > > @event.listens_for(MyThing, "after_parent_attach") > def my_thing_attached(target, parent): > print("Attaching target %s to parent %s", target, parent) > > from sqlalchemy import Table, MetaData, Column, Integer > > Table('t', MetaData(), Column('x', Integer, MyThing())) > > Then you want to register your LazyForeignKey object in a registry that > will allow the callable to be invoked once your “table setup” system has > completed - you’d call the callable, construct a ForeignKeyConstraint, then > append it to the constraints of the parent column.table. > > the only private API in use here is the _set_parent() override. If I > change that API it would be something simple. > -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/groups/opt_out.
