Invertinace mapped type_id to fix value for each child class

32 views
Skip to first unread message

Sören Textor

unread,
Apr 12, 2021, 12:18:32 PM4/12/21
to sqlal...@googlegroups.com
I run into a problem and don't know how to solve it.
The theory is very simple: I habe one base class table with name, id and type column
The child class shall have a unique type_id (all child_class1 objekt shall get type_id 7, all child_class2 objekts type_id = 8, ...)

How can I map the base class typ_id to an hard coded value for eahc class type. 
My actual approach does not change the type_id-columns of Objekt and after saving the objekt the column Objekt.type_id entry is always empty for all entries :-(

class Objekt(db.Model):
    __tablename__ = 'objekt'

    def __init__(self,**kwargs):
        super().__init__(**kwargs)

    id     = db.Column(db.Integer, primary_key=True)
    typ_id = db.Column(db.Integer, db.ForeignKey('objekt_typ.id'))
    typ    = db.relationship("ObjektTyp"
    name   = db.Column(db.String(100))

class ChildClass1(Objekt):
    __tablename__ = 'child_class1'

    @staticmethod
    def typ_id():
        return 7
    
    def __init__(self,**kwargs):
        super().__init__(**kwargs)
        Objekt.typ_id = ChildClass1.typ_id() ### fix type

    id   = db.Column(db.Integer, db.ForeignKey('objekt.id'), primary_key=True)
    text = db.Column(db.String(255 ), default='')

    __mapper_args__ = {
        'polymorphic_identity':'child_class1',
    }


any ideas where to look? I though on polymorphic_on, but I think that does not work because of the fact that type_id ha a foreign key ...

SirAnn

Sören Textor

unread,
Apr 12, 2021, 12:25:30 PM4/12/21
to sqlal...@googlegroups.com
right know I get an error:

c = ChildClass()
db.session.add(c)
db.session.commit()

c.typ -> UnmappedColumnError('No column objekt.typ_id is configured on mapper mapped class ChildClass1->child_class1...')

SirAnn

Simon King

unread,
Apr 12, 2021, 1:06:28 PM4/12/21
to sqlal...@googlegroups.com
I don't understand this comment:

> I though on polymorphic_on, but I think that does not work because of the fact that type_id ha a foreign key ...

As far as I can tell, you ought to have this in the base class:

__mapper_args__ = {
'polymorphic_on': typ_id
}

And this in the subclass:

__mapper_args__ = {
'polymorphic_identity': 7,
}

...and you should get rid of the typ_id function and the
"Objekt.typ_id = ChildClass.typ_id" line.

Does that work for you?

Simon
> --
> SQLAlchemy -
> The Python SQL Toolkit and Object Relational Mapper
>
> http://www.sqlalchemy.org/
>
> To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description.
> ---
> You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/ema56ad245-cad9-4096-8c55-9d75e8d52ea2%40textors-01.

Sören Textor

unread,
Apr 12, 2021, 1:40:44 PM4/12/21
to sqlal...@googlegroups.com
class Objekt(db.Model):
__tablename__ = 'objekt'

def __init__(self,**kwargs):
super().__init__(**kwargs)

id = db.Column(db.Integer, primary_key=True)
typ_id = db.Column(db.Integer, db.ForeignKey('objekt_typ.id'))
typ = db.relationship("ObjektTyp")
name = db.Column(db.String(100))

__mapper_args__ = {
'polymorphic_on': typ_id
}

class ChildObjekt1(Objekt):
__versioned__ = {}
__tablename__ = 'child_objekt1'

@staticmethod
def TypId():
return 7

# User fields
def __init__(self,**kwargs):
super().__init__(**kwargs)
#super().__init__(typ_id=ChildObjekt1.TypId(), **kwargs)

###
id db.Column(db.Integer, db.ForeignKey('objekt.id'),
primary_key=True)
text = db.Column(db.String(255 ), default='')

__mapper_args__ = {
'polymorphic_identity': 7,
}


leads to:
venv\lib\site-packages\sqlalchemy\orm\mapper.py", line 1542, in
_configure_polymorphic_setter
self.polymorphic_on = self._props[self.polymorphic_on]
KeyError: 'typ_id'

raise exception
sqlalchemy.exc.ArgumentError: Can't determine polymorphic_on value
'typ_id' - no attribute is mapped to this name.

maybe i do something totally worg.. I am also using sql continuum

------ Originalnachricht ------
Von: "Simon King" <si...@simonking.org.uk>
An: sqlal...@googlegroups.com
Gesendet: 12.04.2021 19:06:11
Betreff: Re: [sqlalchemy] Invertinace mapped type_id to fix value for
each child class
>To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/CAFHwexeCQd6%2B5-O%3D1H8J8Zmfrg8vDsPmHjLg4PFY9RTySNdJ3w%40mail.gmail.com.

Simon King

unread,
Apr 12, 2021, 2:27:05 PM4/12/21
to sqlal...@googlegroups.com
Here's a standalone working example:

import sqlalchemy as sa
import sqlalchemy.orm as saorm
from sqlalchemy.ext.declarative import declarative_base


Base = declarative_base()


class Objekt(Base):
__tablename__ = "objekt"
id = sa.Column(sa.Integer, primary_key=True)
typ_id = sa.Column(sa.Integer, sa.ForeignKey("objekt_typ.id"))
typ = saorm.relationship("ObjektTyp")
name = sa.Column(sa.String(100))

__mapper_args__ = {
"polymorphic_on": typ_id,
}


class ObjektTyp(Base):
__tablename__ = "objekt_typ"
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String(100))


class ChildObjekt1(Objekt):
__tablename__ = "child_objekt1"
id = sa.Column(sa.Integer, sa.ForeignKey(Objekt.id), primary_key=True)
text = sa.Column(sa.String(255))

__mapper_args__ = {
"polymorphic_identity": 1,
}


class ChildObjekt2(Objekt):
__tablename__ = "child_objekt2"
id = sa.Column(sa.Integer, sa.ForeignKey(Objekt.id), primary_key=True)
text = sa.Column(sa.String(255))

__mapper_args__ = {
"polymorphic_identity": 2,
}


if __name__ == "__main__":
engine = sa.create_engine("sqlite://")
Base.metadata.create_all(bind=engine)
Session = saorm.sessionmaker(bind=engine)

session = Session()
child1type = ObjektTyp(id=1, name="child1")
child2type = ObjektTyp(id=2, name="child1")

child1 = ChildObjekt1(text="child 1 text")
child2 = ChildObjekt2(text="child 2 text")

session.add_all([child1type, child2type, child1, child2])
session.flush()

for obj in session.query(Objekt):
print(obj)


Simon

On Mon, Apr 12, 2021 at 6:40 PM 'Sören Textor' via sqlalchemy
> To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/emf25854f8-548b-4e38-86ce-a540a476e6c3%40textors-01.

Sören Textor

unread,
Apr 12, 2021, 3:58:49 PM4/12/21
to sqlal...@googlegroups.com
Hi Simon
Again you really helped me out. I don't know what point I missed, but
now it works. As usual it's not as simpe le or lets say there are a lot
more code pieces to change before I can really test it in my code. But I
got it.

just one more thing:
I often have to check if a given tpye t the class type. Therefore I
usally use the statci method.

Thus what would you do:

if test_type == ChildClass1().typ_id:
or
if test_type==ChildClass.TypID():

and to ensure only TypId exists fpr that type:
__mapper_args__ = {
"polymorphic_identity": ChildClass.TypID(),
}

And as I said: Thanks a lot!

SirAnn


------ Originalnachricht ------
Von: "Simon King" <si...@simonking.org.uk>
An: sqlal...@googlegroups.com
Gesendet: 12.04.2021 20:26:48
Betreff: Re: Re[2]: [sqlalchemy] Invertinace mapped type_id to fix value
>To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/CAFHwexd_GyPiPs2u1TWmfBb7%3Doab9tS7_4JQoT9Nnq_AgUK%3DuA%40mail.gmail.com.

Simon King

unread,
Apr 13, 2021, 5:14:29 AM4/13/21
to sqlal...@googlegroups.com
I probably wouldn't use this:

if test_type == ChildClass1().typ_id:

...simply because creating an instance of the object just to get
access to the typ_id seems like a waste of effort. If you really need
to check integer typ_id values, the staticmethod approach seems fine.

Simon

On Mon, Apr 12, 2021 at 8:58 PM 'Sören Textor' via sqlalchemy
> To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/emcc41c8d5-e3af-447c-bb85-c674fa674947%40textors-01.
Reply all
Reply to author
Forward
0 new messages