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 [email protected]
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
-~----------~----~----~----~------~----~------~--~---