Use of _polymorphic_map when inheriting

Issue #1407 resolved
Former user created an issue

Hello everyone,

picture a common code location within a company, outside of any application, where database entities would be stored for common use in different applications within that company. In that common area you would store base objects of database entities such as a base object for a contract. That contract base object would be declared using declarative base and would use table information previously gathered through sqlautocode. Also it would include manual relation setups, such as the product this contract is bound to. Optionally it may also contain common logic.

In your application you would inherit from this contract base object and add your application-specific logic to it. The goals of this setup would be: Keep your company wide-used objects in a common place, avoid redundancies.

This pretty much works with SA, as declarative base was designed with inheritance in mind. (kudos!) What does not work, however, is using a custom polymorphic map, when this map would be set up on first inheriting from the base object (you wouldn't want to set up polymorphic mapping in your base object if you don't need this kind of differentiation of your contract objects in all of your applications).

Example scenario:

class ContractBase(Base):
    """ Contract base """
    __tablename__ = 'schema.contract'

    product_list = relation(...)


class Contract(ContractBase):
    """ Contract """
    __mapper_args__ = {'polymorphic_on': contract_table.c.contract_status_id,
                       '_polymorphic_map': ContractStatusPolymorphicMap()}


class ActiveContract(Contract):
    """ Active contract """


class InactiveContract(Contract):
    """ Inactive contract """

(This is a fictional scenario. Please don't care about its use in general and use of a custom polymorphic map in particular.)

In this scenario the polymorphic_on mapper argument is being used. The polymorphic_map argument, however, is "ignored", as it is being overwritten in the _configure_inheritance() call:

            self.polymorphic_map = self.inherits.polymorphic_map

I guess we should only overwrite self.polymorphic_map in _configure_inheritance() if self.inherits.polymorphic_map is not the default (f.e. self.inherits.polymorphic_map is not None and self.polymorphic_map is only being set in the constructor if self.polymorphic_on is not None).

Best Regards, Thomas Wiebe

Comments (5)

  1. Mike Bayer repo owner

    If i understand correctly, the use case is, "we specify a base class, but we don't want to have to implement the "polymorphic_identity" attribute on each subclass. since that is the public interface whereas "_polymorphic_map" is not.

    There's other ways to achieve this without introducing two ways of doing the same thing within SQLAlchemy, such as a custom metaclass, have you considered that ?

  2. Former user Account Deleted

    How cynical of you to think that.

    The polymorphic_identity is a scalar. In case you would have multiple values to identify a class mapping by or even more complex needs, you could use a custom polymorphic map. That's what I interpreted the map as and since Michael once thought out loud the use of the polymorphic map to be "OK", I considered this behaviour unintended.

    If the map is not intended to be used that way, however, I will look into the alternatives.

    Thanks, Thomas

  3. Mike Bayer repo owner

    OK i wasn't attempting to be "cynical", just understanding the request.

    So I've looked at the link you posted, so let me revise what I wrote there.

    i think using the polymorphic_map is OK.

    I'm not sure about that now. I am always willing to add an API or interface that has obvious value, but I am very hesitant, much more so than I was in 2007, to do so unless it's very clear that its the right decision. Basically, if we are proposing a second way to do something that is already possible, other questions to be asked are, is the original way something we should be changing, or removing ? In that letter, I actually proposed polymorphic_identity becoming a list, for example.

    But in fact an entirely better approach, though its more work, is #1131, which addresses all of the issues you've posted here, including #1407, #1408, #1409. The #1131 interface would solve this issue completely and would be a clean progression of finer grained control than what polymorphic_identity provides.

    i downplayed its existence
    since I felt it was confusing to people, which is also the reason i
    made the _polymorphic_map argument to mapper "private"; it was
    originally public.

    its still "private". I still feel that two slightly different ways of doing the same thing is confusing.

    Basically I would rather shoot for a single feature that accomplishes the full range of use cases.

  4. Log in to comment