Hi John,

Check out the doc section entitled "Mapping a class with table
inheritance":
http://www.sqlalchemy.org/docs/adv_datamapping.html#advdatamapping_inheritance
Although it's not the only way to do it, you might be interested in
polymorphic multiple-table inheritance, which SQLAlchemy already
handles really well.

As for your current code: if set up for polymorphic inheritance,
sqlalchemy will handle the connection of an object with the proper
table for its type and you won't need that select statement in your
__init__ method at all.  Furthermore, sqlalchemy doesn't even call
your __init__ methods when it loads items from storage; it uses
__new__ (see item 5.6 on the FAQ page for explanation: "why isn't my
init called when i load objects?"). Init is just for when you first
make a new object of your own, before you've ever persisted the
object.

Read and ye shall find!

Here is a reworked version that has the behavior you might be looking
for:

from sqlalchemy import *
#..other imports

engine = create_engine('mysql://[EMAIL PROTECTED])  #example uri
metadata = BoundMetaData(engine)

items_table = Table('items', metadata,
    Column('id', Integer, primary_key = True),
    Column('item_type', String(20))
    # add any other columns here for properties that should be
    # carried by every item regardless of its item_type
)

tools_table = Table('tools', metadata,
    Column('item_id', Integer, ForeignKey('items.id'),
primary_key=True),
    Column('tool_name', String(20)))
    # add any other columns for properties of tools only

widgets_table = Table('widgets', metadata,
    Column('item_id', Integer, ForeignKey('items.id'),
primary_key=True),
    Column('widget_name', String(20)))
    # add any other columns for properties of widgets only

# class definitions
class Item(object):
    def __init__(self, item_type):
        self.item_type = item_type
        # id will be provided automatically

class Tool(Item):   ## <-- note the inheritance
    def __init__(self, tool_name):
        self.tool_name = tool_name
        # etc., set any other values for tools_table columns
    def __repr__(self):
        return 'Tool (%s)' % self.tool_name

class Widget(Item):
    def __init__(self, widget_name):
        self.widget_name = widget_name
        # etc., set any other values for widgets_table columns
    def __repr__(self):
        return 'Widget (%s)' % self.widget_name

item_join = polymorphic_union(
    {
        'tool': items_table.join(tools_table),
        'widget': items_table.join(widgets_table),
        'item': items_table.select(items_table.c.item_type=='item'),
    }, None, 'ijoin')
# note: by assigning an item type 'item' you can create generic items
# which are neither tools nor widgets (etc.)

item_mapper = mapper(Item, items_table,
    select_table = item_join,
    polymorphic_on = item_join.c.item_type,
    polymorphic_identity = 'item')

tool_mapper = mapper(Tool, tools_table,
    inherits=item_mapper,
    polymorphic_identity='tool')

widget_mapper = mapper(Widget, widgets_table,
    inherits=item_mapper,
    polymorphic_identity='widget')

# note, no need to name the mappers if you don't wish to
# refer to them later

if __name__ == '__main__':
    metadata.create_all()
    session = create_session()

    metadata.engine.echo = True
    item1 = Tool('sample hammer')
    item2 = Tool('screwdriver')
    item3 = Widget('spam')
    item4 = Widget('eggs')

    # note: items don't *have* ids until saved AND flushed
    # note also: item ids are assigned automatically

    session.save(item1)
    session.save(item2)
    session.save(item3)
    session.save(item4)
    session.flush()

    allitems = session.query(Item).select()
    metadata.engine.echo = False
    for item in allitems:
        print item.id, item

    session.close()
    metadata.drop_all()


On Jun 5, 6:20 pm, John Lorance <[EMAIL PROTECTED]> wrote:
> I'm newish to SqlAlchemy and for the life of me I can't figure out how
> to properly set things up so that lookup tables(objects) are cached
> and/or it is easy for new parent objects to associate to their
> childing upon initialization.  See below for code snippet and sample
> problem.
>
> from sqlalchemy import *
> #..other imports
>
> metadata = MetaData()
>
> item_types_table = Table('item_types', metadata,
>     Column('id', Integer, autoincrement=False, primary_key = True),
>     Column('name', String(50))
> )
>
> items_table = Table('items', metadata,
>     Column('id', Integer, primary_key = True),
>     Column('item_type_id', Integer, ForeignKey('item_types.id')),
>     Column('name', String(150))
> )
>
> engine = create_engine('mysql://[EMAIL PROTECTED])  #example uri
> engine.echo = True
> metadata.create_all(engine)
>
> # class definitions
> class ItemType(object):
>     def __init__(self, id, name=None):
>         self.id = id
>         self.name = name
>
> class Item(object):
>     def __init__(self, type_name, name):
>        self.item_type =
> session.query(ItemType).selectfirst(ItemType.c.name==type_name)
>        #  ^^^^ Is there a better way to create this association?
>
>        self.name = name
>
> mapper(ItemType, item_types_table)
> mapper(Item, item_table, properties = dict(
>     item_type = relation(ItemType)
>     )
> )
>
> session = create_session(bind_to=engine)
>
> #create item types
> t1 = ItemType(0, 'tool')
> t2 = ItemType(1, 'widget')
> session.save(t1)
> session.save(t2)
>
> # ####### Everything works above as expected
>
> item1 =Item('tool', 'sample hammer')
> item2 =Item(''tool', 'screwdriver'')
>
> #end of code
> ####################
>
> So two questions.
> 1) Upon encountering the last line of code, I see that when I look at
> the SQL generated, i see that the select called in the Item __init__
> method is sending a query again, instead of using what should in
> theory by in the object cache for the exact same query.
>
> 2) Basically, I'm trying to get new Item objects to relate to the
> correct Item Type via using the name to create the foreignkey (id)
> relationship.  So the questions is, is the Item Init method setup
> right for this, or is there a better way?


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

Reply via email to