Markus Meskanen Markus Meskanen - 1 year ago 58
Python Question

Use base class's property/attribute as a table column?

A game engine provides me with a

Player
class with a
steamid
property (coming from C++, this is just a basic example on what it would look like in Python):

# game_engine.py

class Player:

def __init__(self, steamid):
self.__steamid = steamid

@property
def steamid(self):
return self.__steamid


I then proceed to subclass this class while adding a
gold
attribute:

# my_plugin.py

class MyPlayer(game_engine.Player, Base):
gold = Column(Integer)


Now I need to store the player's
gold
to a database with the player's
steamid
as a primary key to identify the player. How do I tell SQLAlchemy to use the base class's
steamid
property as the primary key?

Here's something silly I tried:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property

import game_engine

Base = declarative_base()

class Player(game_engine.Player, Base):
__tablename__ = 'player'

_steamid = game_engine.Player.steamid

@hybrid_property
def steamid(self):
return type(self)._steamid.__get__(self)


But yeah, it was a long shot...

sqlalchemy.exc.ArgumentError: Mapper Mapper|Player|player could not assemble any primary key columns for mapped table 'player'

Answer Source

This is simpler than you might expect. The solution below is roughly equivalent to the one from r-m-n, but more straightforward because it uses modern declarative mapping. There is no need for @hybrid_property, you can just inherit steamid from the parent class.

# my_plugin.py

class MyPlayer(game_engine.Player, Base):

    def __init__(self, steamid, gold):
        super().__init__(steamid)
        self._id = self.steamid
        self.gold = gold

    _id = Column('steamid', Integer, primary_key=True)
    gold = Column(Integer)