Single Table Inheritance, multiple mappers and default (base) mapper

51 views
Skip to first unread message

kris

unread,
Dec 7, 2011, 2:53:16 AM12/7/11
to sqlal...@googlegroups.com

I am using a single table scheme to store for a set of resource types.

I would like to load a specific class if a mapper is defined and use the base class if no
more specific version can be found.   Is there a way to do this?
i.e.
resource  = Table('resource', 
                           Column('resource_type',  String),
                           ...

I also have a set of predefined helper classes
class Resource, Resource_A, Resource_B, 

mapper(Resource, ...
       polymorphic_on = resource.c.resource_type,                                                                   
       #polymorphic_identity = ''*"  # I think I need something like this
mapper(Resource_A,...
       polymorphic_on = resource.c.resource_type,                                                                   
       polymorphic_identity = ''A"
mapper(Resource_B,...
       polymorphic_on = resource.c.resource_type,                                                                   
       polymorphic_identity = ''B"


Now if I have inserted types 
A = Resource_A()
B = Resource_B()
C = Resource()
C.resource_type = "C"
D = Resource()
D.resource_type = "D"
session.add([A,B,C,D])

And then I do 
session.query(Resource)

Is there a way to specify the polymorphic_identity of Resource is default ?

Thanks.

                       

Michael Bayer

unread,
Dec 7, 2011, 12:53:53 PM12/7/11
to sqlal...@googlegroups.com

sure, just put a polymorphic_identity on your base Resource class and that's the class you'll get if that identity value is the one retrieved from the row.

However in your example above, the Resource you have where you stuck a "D" on it, you'd get a Resource_D back when querying. It's best not to manually set discriminators like that as you'll have inconsistent typing between the "to be flushed" set of objects and the "returned from a query" set.

kris

unread,
Dec 7, 2011, 11:08:56 PM12/7/11
to sqlal...@googlegroups.com
Hmm, I think I want the opposite behavior.  I was the defualt mapper to Resource unless a more specific mapper has been defined.
I never defined a 'C' or 'D' and I would like simple get a Resource when no better mapper is found. 
i.e. I get Resource class for C, D and get a Resource_A for A and a Resource_B for B.  

Is this possible?

Michael Bayer

unread,
Dec 8, 2011, 11:27:34 AM12/8/11
to sqlal...@googlegroups.com
So you're looking for a row that has "C" or "D" in it to act as though it were "default".    As an easy feature, that is ticket #2238 set on the 0.8 milestone.

the workaround for now is to use column_property() in conjunction with a case() statement, I've posted the recipe for that at http://www.sqlalchemy.org/trac/wiki/UsageRecipes/CaseBasedPolymorphicOn .

It will work in 0.7.3 but not in the current tip as there is a bug preventing it from working.




--
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To view this discussion on the web visit https://groups.google.com/d/msg/sqlalchemy/-/FHmjireFL_EJ.
To post to this group, send email to sqlal...@googlegroups.com.
To unsubscribe from this group, send email to sqlalchemy+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.

Michael Bayer

unread,
Dec 8, 2011, 11:43:22 AM12/8/11
to sqlal...@googlegroups.com
the recipe is broken, please wait until i have time to fix it, thanks.

Michael Bayer

unread,
Dec 8, 2011, 11:57:54 AM12/8/11
to sqlal...@googlegroups.com
OK it works (not yet in tip though).

kris

unread,
Dec 8, 2011, 12:49:02 PM12/8/11
to sqlal...@googlegroups.com
Does this mean I can use this in 7.3?  or Do I need to download tip?

Also could you show me how this would work with old style mapper(...) s instead of declarative_base?

Thanks,
Kris

Michael Bayer

unread,
Dec 8, 2011, 1:55:14 PM12/8/11
to sqlal...@googlegroups.com
works in 0.7.3.  will also work in 0.7.4  Just not the current tip at the moment.

the regular mapper() setup is equivalent (see http://www.sqlalchemy.org/docs/orm/mapper_config.html#classical-mappings) :

discriminator_expr = case(...)

mapper(Person, ..., polymorphic_on=discriminator_expr, polymorphic_identity='person', properties={
    'discriminator':column_property(discriminator_expr)
})

@event.listens_for(Person, ...)
...

note the "event" part of this is just to set the "type" column automatically, it's not required.


--
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To view this discussion on the web visit https://groups.google.com/d/msg/sqlalchemy/-/i2RCGGlPyKsJ.
Reply all
Reply to author
Forward
0 new messages