[Grok-dev] megrok.rdb, Oracle, and views.

Jeffrey D Peterson bgpete at gmail.com
Fri Feb 12 13:10:30 EST 2010


I started a how-to as mentioned, It's not quite finished and I am out of
time for now but I will get back at it ASAP.

> -----Original Message-----
> From: Sebastian Ware [mailto:sebastian at urbantalk.se]
> Sent: Friday, February 12, 2010 3:06 AM
> To: Jeffrey D Peterson
> Cc: 'Martijn Faassen'; grok-dev at zope.org
> Subject: Re: [Grok-dev] megrok.rdb, Oracle, and views.
> 
> Jeffrey! This is fantastic research you have done. Please post this as
> a howto on grok.zope.org! If you don't have time to format it, just
> post it as text only.
> 
>    register and login
> 
>    http://grok.zope.org/join_form
> 
>    and go to
> 
>    http://grok.zope.org/documentation/how-to/
> 
>    and add howto.
> 
> Mvh Sebastian
> 
> 12 feb 2010 kl. 01.26 skrev Jeffrey D Peterson:
> 
> > Hello again,
> >
> > A while back we looked at some issues I was having with megrok.rdb,
> > Oracle
> > and reflecting views.  I had fiddled around with megrok.rdb until I
> > got what
> > seemed like something that worked, and it did, but it was a little
> > hack-is,
> > pulling stuff out of the metadata to not create it.  Well after
> > several
> > emails with the sqlalchemy list, I think I have a better solution,
> > this is
> > based mostly on advice from Michael Bayer about how views should be
> > handled
> > in SQLA.
> >
> > His suggestion was very simple...keep them in a separate metadata
> >
> > So, to that end, here is what it looks like to me.
> >
> > Setup stuff (oracled.py):
> >
> > DSN = 'oracle://webserv@MIGR75X'
> > engine_factory = EngineFactory(DSN, echo=True)
> > grok.global_utility(engine_factory, direct=True)
> >
> > scoped_session = GloballyScopedSession()
> > grok.global_utility(scoped_session, direct=True)
> >
> > # Keep two metadata and fire up engines for both
> > reflected_views_md = rdb.MetaData()
> > created_md = rdb.MetaData()
> >
> > @grok.subscribe(IEngineCreatedEvent)
> > def reflected_engine_created(event):
> >    rdb.setupDatabase(reflected_views_md, True)
> >
> > @grok.subscribe(IEngineCreatedEvent)
> > def engine_created(event):
> >    rdb.setupDatabase(created_md)
> >
> >
> > Changes in megrok.rdb:
> >
> > In setup.py I simply added a parameter and conditional to the
> > setupDatabase
> > function:
> >
> > def setupDatabase(metadata, skip_create=False):
> >    """Set up of ORM for engine in current site.
> >
> >    This will:
> >
> >    * reflect any reflected tables that need to be reflected from the
> > database
> >      into classes.
> >
> >    * create any tables in the database that haven't been yet
> > reflected.
> >    """
> >    reflectTables(metadata)
> >    if not skip_create:
> >        createTables(metadata)
> >    notify(DatabaseSetupEvent(metadata))
> >
> >
> > Then when reflecting views simply use the correct metadata and set
> > the flag
> > skip_create to True. The reason there was always trouble was that
> > rdb.setupDatabase _always_ called create_all() regardless. SQLA,
> > while it
> > can see that reflected tables exist in the DB it can't do the same
> > with
> > views and would try and create those views as tables if create_all()
> > was
> > called with the metadata containing the reflected views.
> >
> > This is a very small subtle change that would not at all effect
> > existing
> > code.
> >
> > And then you can fire up reflected views to your heart's content:
> >
> >
> > from portal.lib.db.oracled import reflected_views_md as metadata1,
> > created_md as metadata2
> >
> > class TestSA(rdb.Container):
> >    pass
> >
> > class CrarySalesPart(rdb.Model):
> >    """
> >    Reflected view, notice the metadata that uses the
> > rdb.setupDatabase with
> > skip_create=True,
> >    Don't run create_all() on this metadata SQLA will see this as a
> > table
> > that needs creation and
> >    Try and create it in the DB, which we do not want.
> >    """
> >    rdb.metadata(metadata1)
> >    rdb.reflected()
> >    rdb.tablename('crary_sales_part')
> >    rdb.tableargs(schema='crar1app', useexisting=True)
> >
> >    contract = Column('contract', String, nullable=False,
> > primary_key=True)
> >    catalog_no = Column('catalog_no', String, nullable=False,
> > primary_key=True)
> >
> > class CraryOutputTab(rdb.Model):
> >    """
> >    Reflected table, notice the metadata that uses the
> > rdb.setupDatabase
> > with skip_create=False(default),
> >    SQLA handles the create properly because it can see this as a
> > table and
> > therefore will not try and create it.
> >    This metadata would then also be used for any tables you did want
> > to be
> > dynamically created as well.
> >    """
> >    rdb.metadata(metadata2)
> >    rdb.reflected()
> >    rdb.tablename('crary_output_tab')
> >    rdb.tableargs(schema='crar1app', useexisting=True)
> >
> >
> > I don't know about you but this method feels right to me, and it
> > also causes
> > a lot less pain.
> > Very little code to change and a lot of functionality gained.
> >
> > Here is a diff of setup.py:
> >
> > 10c10
> > < def setupDatabase(metadata):
> > ---
> >> def setupDatabase(metadata, skip_create=False):
> > 21c21,22
> > <     createTables(metadata)
> > ---
> >>    if not skip_create:
> >>        createTables(metadata)
> >
> >
> > Regards,
> >
> > Jeff Peterson
> >
> > _______________________________________________
> > Grok-dev mailing list
> > Grok-dev at zope.org
> > https://mail.zope.org/mailman/listinfo/grok-dev



More information about the Grok-dev mailing list