On Wed, Jan 26, 2011 at 6:35 AM, Daniel Holth <[email protected]> wrote:
> Why bother wrapping sqlalchemy.engine_from_config? That part seems to take
> up most of the code in add_engine(), but when a user has an oddball database
> they have to read and understand the wrapper before they can stop using it.
> This particular issue was a sore point for me using Pylons' SQLAlchemy
> config from the paster template.
>
> Oddball example:
>
> def create_special():
>     return dbapi.connect('odd database')
>
> import sqlalchemy
> e = sqlalchemy.create_engine('oddball://database', creator=create_special)
> pyramid_sqla.add_engine(engine=e)
>
> I think you should just require *two* extra lines of boilerplate:
>
> import sqlalchemy
> e = sqlalchemy.engine_from_config(settings)
> pyramid_sqla.add_engigne(engine=e)
>
> Users can learn more SQLAlchemy and less pyramid_sqla, confident that
> add_engine is not doing any magic.

Hi there. I went back and forth on that point, but came down on the
side that most users have one straightforward database and would like
the streamlining of one configuration line. It can handle your
situation too:

# With DB URL in INI file
pyramid_sqla.add_engine(settings, creator=create_special)

# With DB URL as constant
dburl = "oddball://database"
pyramid_sqla.add_engine(url=dburl, creator=create_special)

One minor annoyance with SQLAlchemy is that you have to import this
from here, that from there, and yon from somewhere else just to
assemble the required boilerplate code. pyramid_sqla provides one way
to simplify this, and the entire module is so small that I think it's
pretty easy to understand and verify it's not doing much magic.

> How do I configure a Session() that talks to more than one database? A
> SQLAlchemy session can have more than one bind:
> Session.configure(binds={User:engine1, Account:engine2})
> (http://www.sqlalchemy.org/docs/orm/session.html#enabling-two-phase-commit).
> SQLAlchemy will persist each class with its respective database engine.

Did you see the usage page? It's under "Different tables bound to
different engines".
https://bytebucket.org/sluggo/pyramid_sqla/wiki/html/usage.html

"""
pyramid_sqla.add_engine(settings, name="engine1", prefix="engine1.")
pyramid_sqla.add_engine(settings, name="engine2", prefix="engine2.")
Session = pyramid_sqla.get_dbsession()
import myapp.models as models
binds = {models.Person: engine1, models.Score: engine2}
Session.configure(binds=binds)

The keys in the binds dict can be SQLAlchemy ORM classes, table
objects, or mapper objects.
"""

> I encourage you to test your code without _base.metadata.bind = x. Mine
> works fine without it, and it is easier to persist the same table to more
> than one database engine if the metadata is not bound.

That's an unusual use case. It's under "Two engines, but no default engine".

"""
In this scenario, two engines are equally important, and neither is
predominent enough to deserve being the default engine. This is useful
in applications whose main job is to copy data from one database to
another.

pyramid_sqla.init_dbsession()
pyramid_sqla.add_engine(settings, name="engine1", prefix="engine1.")
pyramid_sqla.add_engine(settings, name="engine2", prefix="engine2.")

Because there is no default engine, queries will fail unless you
specify an engine every time using the bind= argument or
engine.execute(sql).
"""

This gets into the part of pyramid_sqla I'm least satisfied with. The
'name' argument in the above two examples is the most complex part of
the package.  If it's not specified or the value is "default", this
engine is considered the "default engine"  and is bound to the Session
and metadata. If a name *is* specified, these are not done. The first
example is actually a superset of the second, because any application
that uses 'binds' would probably not have an default engine. I'm
hoping people don't get lost in the differing ways to use 'name' and
how it's sometimes similar to 'prefix'.

All this shows that there are several ways to structure your engines
and models, and it's hard to fit them all into a few functions with
consistent arguments, while still keeping the simplest and most common
use case simple. An earlier draft had a 'init_dbsession()' function
which accepted a 'session_args' argument or sessionmaker, which is
where you would put custom session args like 'binds'. But that seemed
like unnecessary complication because not many people would ever use
that feature, and it's just as easy for them to get the Sessin and
call .config() themselves.

I think the current API covers 80% of the use cases by default, and
with customization can accommodate 95% of them. Most users have only
one database, many want less boilerplate configuration in their
application, and many are new to SQLAlchemy and Python and just want
it to work out of the box so that they can focus on their model
classes. If you find that part of the docs aren't clear enough, I can
work on those sections.

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