I guess being able to refer to the bases from third party libraries is
important.

Here is the use case I am working on now.

I am currently writing classes for User, Group, Permission to store
security data.

But since this scheme would be used in subsequent applications, I will
separate it into a separate module as a library, to use it with later
apps.

These classes are in the form of sqlalchemy Mixin classes. However,
the code includes a many-to-many relationship, which needs an
association table. Constructing a table in sqlalchemy needs to
reference the metadata of your declarative base.

user_groups = Table('user_groups', base.metadata,
                        Column('user_id', Integer,
ForeignKey('User.id')),
                        Column('group_id', Integer,
ForeignKey('Group.id'))
                        )

class UserMixin(object)
    @declared_attr
    def groups(self):
        return relationship("Group", secondary=user_groups)


So you see, without the ability to refer to my application base, I
cannot add this part of to the boilerplate code in the separate
library and will have to recode it everytime I will start coding a new
app, which decreases the utility of code reuse.

I was then wondering if this is a good use case for sqlahelper.

#get my application's declarative base (thru sqlahelper)
import  sqlahelper
base = sqlahelper.get_base()

user_groups = Table('user_groups', base.metadata,
                        Column('user_id', Integer,
ForeignKey('User.id')),
                        Column('group_id', Integer,
ForeignKey('Group.id'))
                        )

class UserMixin(object)
    @declared_attr
    def groups(self):
        return relationship("Group", secondary=user_groups)


Ahmed



On Dec 28, 4:36 pm, Mike Orr <[email protected]> wrote:
> On Tue, Dec 27, 2011 at 8:05 AM, Michael Bayer <[email protected]> 
> wrote:
> > What's the use case for a Base being shared to a third party module that 
> > doesn't know about your application?  This sounds like a bad idea.   A Base 
> > might have any number of behaviors on it, like certain columns, naming 
> > conventions, __mapper_args__(), attribute names, that can't be anticipated 
> > by a third party library.
>
> The problem is that applications and libraries are all creating their
> own Bases and Sessions, and then it becomes complicated to make them
> work together. So we need to figure out some common way to handle
> this, so that they can all cooperate, and the application can make the
> library use its Session and Base if it wants to. Because some
> libraries are just defining a few tables with a name prefix, and don't
> need a separate database.
>
> > That said I have a feeling some libraries are already doing this but I wish 
> > we could work out a better way than using inheritance as a third party 
> > plugin point - one of Ben's key rationales for dumping Pylons altogether is 
> > that it was built on this model for extensibility.
>
> Ben has also been recommending SQLAHelper.
>
> Originally SQLAHelper was created to avoid circular imports or a
> 'meta' module in the model. Pylons used a 'model.meta' module to hold
> the Session, Base, and engine. We wanted to avoid that in Pyramid, but
> we also wanted to avoid defining the Session and Base in
> model.__init__, which submodules would import, thus creating a
> circular import. So SQLAHelper replaced the 'meta' module, and because
> it's preinitialized so it can be imported at any time. The issue about
> how it could also help in this cooperation between the application and
> libraries was discovered later.
>
>
>
>
>
>
>
>
>
> >> But when you start getting multiple databases in the
> >> application, it may get beyond what the shared Base can provide. In
> >> that case, you can decide whether one database is general-purpose,
> >> used by several modules and third-party libraries, while another
> >> database is single-purpose, used only by one module. Then there's a
> >> clear answer: use SQLAHelper's Base for the shared database, and your
> >> own Base for the single-purpose database. For instance, the second
> >> database may be specifically for site statistics, searching, an
> >> external database you're consulting, etc. These would all be
> >> single-purpose databases, which wouldn't have to be shared.
>
> > Why not standardize SQLAHelper on a "one by default, many if desired" model 
> > ?    Also as an alternative to the getter/setter style, why not just:
>
> > helper = SQLAHelper()
>
> > # default objects: "base", "session", "engine":
>
> > default_base = helper.base
> > default_session = helper.session
> > helper.engine = create_engine(...)
>
> > # namespaces for each, "default" points to the "default":
>
> > helper.bases.default is helper.base
> > helper.sessions.default is helper.session
> > helper.engines.default is helper.engine
>
> > # alternates to the "default":
>
> > helper.bases.generic_base = Base()
> > helper.sessions.alternate_session = scoped_session(...)
> > helper.engines.alt1 = create_engine(...)
>
> > I think multiple sessions should be supported.  My current app uses two 
> > simultaneously as many classes are represented in two different databases 
> > at the same time - one is the "live" database the other is "historical".    
> > An application that switches between "master" and "slave" databases at the 
> > session level needs to do this also.
>
> Well, I'm inclined to do whatever MikeB suggests. But what would the
> module contain in this case; i.e., what would its globals be? You'd
> still need a module with globals in order to be a well-known rendevous
> point. 'helper = SQLAHelper()' as a variable in the application
> doesn't do that. Or would 'helper' be the global in the package?
>
> One thing SQLAHelper does is that if you call ``add_engine(engine)``
> without an engine name, it becomes the default engine, and the Session
> and Base.metadata are automatically bound to it. This is so that
> applications with a single database only need to make one function
> call to set everything up. It looks like the only way to do that in
> your 'helper' structure would be a 'helper.set_default_engine()'
> method? And 'helper.engines.default' would be None initially, because
> the engine is not known at import time?
>
> --
> Mike Orr <[email protected]>

-- 
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