thank you michael, very helpful points. 

in the end i'll just use PostgreSQL native schema since i'm not able to get 
the multi-connection thing working. for that i use a common ``
DeclarativeBase`` and ``__table_args__ = {'schema': 'market'}`` or 
``__table_args__ 
= {'schema': 'site'}``.

i'm still interested in the solution 
of 
http://docs.sqlalchemy.org/en/rel_0_7/orm/session.html#simple-vertical-partitioning
 
since it toke me some time and i don't like having such an open issue ;) 
this is my original scenario, having two ``DeclarativeBase``, one for the ``
site``, one for the ``market``. As you said, i changed the relationship to 
``user = sa.orm.relationship(User, foreign_keys=[User.id])`` which changes 
the exception to::

sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 
'product_items.user_id' could not find table 'users' with which to generate 
a foreign key to target column 'id'

this happens even though the schema is also assigned in the ``User`` class::

@timestampable()
class User(DeclarativeBase):

    # necessary to create references from the market to this users
    __table_args__ = {'schema': SITE_DATABASE_SCHEMA_NAME}

    id = sa.Column(sa.BigInteger,
        Sequence('users_seq_id', optional=True),
        primary_key=True)

here is the changed code in in the ``market``::

def initialize_sql(config, engine, user_engine=None):
    session_maker = sessionmaker()
    DBSession = scoped_session(session_maker)
    DBSession.configure(bind=engine)
    DBSession.configure(binds={
        ProductItem: engine,
        User: user_engine
    })
    log.debug('bind market engine')
    Base.metadata.bind = engine
    # danger: here we try to autogenerate the schema
    # Base.metadata.create_all(engine)

    # db-session per request
    # @see: 
http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/database/sqlalchemy.html#using-a-non-global-session

    def db(request):
        log.debug('add DB session to request')
        maker = request.registry.dbmaker
        session = maker()

        def cleanup(request):
            session.close()
        request.add_finished_callback(cleanup)
        return session

    config.registry.dbmaker = session_maker
    config.set_request_property(db, name='dbsession', reify=True)
    # for pyramid 1.4 use: ``config.add_request_method(db, reify=True)``


class ProductItem(Base):
    """
    cross-db references:
    - 
http://stackoverflow.com/questions/6433592/cross-database-join-in-sqlalchemy
    - http://markmail.org/message/z5tdtlcuoth2osqm

    schemas:
    http://www.postgresql.org/docs/9.1/static/ddl-schemas.html
    """
    __tablename__ = 'product_items'
    __table_args__ = {'schema': MARKET_DATABASE_SCHEMA_NAME}

    id = sa.Column(sa.BigInteger,
                   Sequence('place_seq_id', optional=True),
                   primary_key=True)
    name = Column(Unicode(255), unique=True)
    user_id = sa.Column(
        sa.BigInteger,
        sa.ForeignKey('%s.%s.id' % (SITE_DATABASE_SCHEMA_NAME, 
User.__tablename__)),
        primary_key=True
    )
    user = sa.orm.relationship(User, foreign_keys=[User.id])

do you have a hint how to tell sqlalchemy to choose ``site.users`` rather 
than ``users`` as table?

thanks a lot, 
andi

On Friday, 26 April 2013 00:32:32 UTC+2, Michael Bayer wrote:
>
>
> On Apr 25, 2013, at 10:21 AM, Andi Blake 
> <[email protected]<javascript:>> 
> wrote:
>
> hi all, 
>
> i have a webapp with an existing database-model ``site``, including users. 
> in a second service i create a new database-model ``market``, but still 
> want to access the users (which works via separate engine).
>
> goal: i want to create a relation from the ``market``-model to the 
> ``site``-model. e.g. referencing a ``User`` instance from the 
> ``site``-model to the ``market``-model. like this::
>
>
> SITE_DATABASE_SCHEMA_NAME = 'site'
> MARKET_DATABASE_SCHEMA_NAME = 'market'
>
> def initialize_sql(engine, user_engine = None):
>     DBSession = scoped_session(sessionmaker(bind=engine))
>     DBSession.configure(bind=engine)
>     log.debug('bind market engine')
>     Base.metadata.bind = engine
>     # danger: here we try to autogenerate the schema
>     # Base.metadata.create_all(engine)
>
>     if user_engine:
>         log.debug('bind user engine')
>         DeclarativeBase.metadata.bind = user_engine
>
> class ProductItem(Base):
>     """
>     cross-db references:
>     - 
> http://stackoverflow.com/questions/6433592/cross-database-join-in-sqlalchemy
>     - http://markmail.org/message/z5tdtlcuoth2osqm
>
>     schemas:
>     http://www.postgresql.org/docs/9.1/static/ddl-schemas.html
>     """
>     __tablename__ = 'product_items'
>     __table_args__ = {'schema': MARKET_DATABASE_SCHEMA_NAME}
>
>     id = sa.Column(sa.BigInteger,
>                    Sequence('place_seq_id', optional=True),
>                    primary_key=True)
>     name = Column(Unicode(255), unique=True)
>     user_id = sa.Column(
>         sa.BigInteger,
>         sa.ForeignKey('%s.%s.id' % (SITE_DATABASE_SCHEMA_NAME, 
> User.__tablename__)),
>         primary_key=True
>     )
>     # this one fails
> *    user = sa.orm.relationship("User")*
>
>
> question: 
>
> - is this possible?
> - how can i attach the missing ``User`` class to the known classes for 
> that sqlalchemy session? now of course i get::
>
> sqlalchemy.exc.InvalidRequestError: When initializing mapper 
> Mapper|ProductItem|product_items, expression 'User' failed to locate a name 
> ("name 'User' is not defined"). If this is a class name, consider adding 
> this relationship() to the <class 
> 'if_market.models.ProductItem.ProductItem'> class after both dependent 
> classes have been defined.
>
>
>
> there's two different concepts happening here.
>
> One is that the relationship("User") can't find a class named "User".   
> You'd need to define a "User" class in addition to "ProductItem" using the 
> same Base, or if on a different Base then you need to say 
> relationship(User) without the quotes.  This is not really related to the 
> concept of multiple engines so much (it seems like it is, but it isn't at 
> any fundamental level).
>
> The other is there's a multiple connection use case here, but it's not 
> clear what the boundaries are since the term "database-model" is ambiguous. 
>  
>
> If you're on a system like Postgresql, and your two sets of tables are in 
> different schemas within the same database, a single connection can refer 
> to both sets of tables at once, by specifying a schema name for the 
> "remote" set of tables (or for both).   A query would look like "SELECT * 
> FROM someschema.mytable".   Postgresql and other databases also feature 
> extensions to access tables in other databases and even remote servers all 
> from one connection.    These techniques are worth looking into if you 
> really need to perform queries against both sets of tables simultaneously.
>
> If you can deal with running more than one connection at a time, and 
> having separate SELECT statements emitted for different connections, then 
> you can configure a Session with an engine per mapper.  We call this 
> "vertical partitioning" and there's some background on that here: 
> http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html#simple-vertical-partitioning.
>  
>   It's a little bit of a DIY-route to travel.
>
> I think the important thing is to be familiar with the concepts of tables, 
> schemas, databases, and connections, and to look at the problem from that 
> perspective first.   Then applying an object-oriented "model" around all 
> that is after you've determined how the actual database access is to happen 
> first.
>
>
>
>
>

-- 
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?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to