Markus Meskanen Markus Meskanen - 4 months ago 12
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

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)
Comments