On Dec 16, 2011, at 3:23 AM, Michael Merickel wrote:

> In SQLAlchemy the "metadata" is the central object that binds tables together 
> and describes their relationships. It is not possible to describe 
> relationships between tables that are defined using different metadata 
> objects.

you can but it's tedious - either ForeignKey(myothertable.c.id)  or use 
primaryjoin + foreign_keys inside of each relationship().


> As you know already, each Base creates its own shared metadata object between 
> all of its subclasses. If you really do want to share tables between addons 
> you either need to define that table per-metadata-object, or share those 
> particular objects via a common package.

You can share a single MetaData object with multiple Base objects by passing it 
in as an argument to declarative_base().   However, and this is something that 
should be improved, MetaData is only the registry of name->Table objects, not 
the *other* registry of name->Class objects (and at this point Chris is 
scratching his head like "What??? Why???"...its part of the Core/ORM separation 
plus a lot of history).  

Both registries are used in different contexts, name->Table for the ForeignKey 
object basically (and in some cases parts of relationship()), and name->Class 
for the arguments passed orm.relationship() function.

You can make two Base objects totally on top of the same registries like:

Base1 = declarative_base()
Base2 = declarative_base(metadata=Base1.metadata)
Base2._decl_class_registry = Base1._decl_class_registry

but what does this imply ?   That you wouldn't have any same-named classes on 
top of Base1 and Base2.   That's why you might not want to do that.   There's a 
ticket to extend declarative to support full packagenames in the "class" 
registry like relationship("mypackage.MyClass"), though that's not how everyone 
might want to operate.   Similarly, MetaData has to do with tables, a multi-DB 
app may have any particular pattern of repeated table names across multiple DBs 
so the ability to control those registries is still important.

There's two other ways to make yourself a Base that extends from a "common" 
Base.  The most common is to send cls:

Base2 = declarative_base(cls=MyAppsUberBase)

There's also now an __abstract__ flag that does this:

class MyLocalBase(Base):
    __abstract__ = True

   # custom things on my local apps' base

That pattern hasn't been tested as much but should in theory be very useful.


> 
> If you'd like to also share the mapper relationships then you'll need to 
> share the Base subclasses (User, Product, etc).

If this means, the classes must be on the same Base to use relationship() 
between them, that's not true.    The docs are pretty clear that relationship() 
has no dependency on declarative, and that any declarative class is just a 
syntactic trick for mapper(MyClass, mytable).   You can pass any mapped class 
or mapper() to relationship().  It's just the "look it up from the string" part 
that uses the local registry.   To help with resolving import time issues, you 
can also send a callable like this:

relationship(lambda: MyOtherClass)


> 

-- 
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/pylons-discuss?hl=en.

Reply via email to