2016-07-28 8 views
6

игра двигатель дает мне Player класса со свойством steamid (исходя из C++, это просто простой пример о том, что он будет выглядеть в Python):Использовать свойство/атрибут базового класса в качестве столбца таблицы?

Я затем перейти к подклассу этого класса при добавлении атрибута gold:

# my_plugin.py 

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

Теперь мне нужно хранить игрок gold к базе данных с игроком steamid в качестве первичного ключа для идентификации игрока. Как указать SQLAlchemy использовать свойство базового класса steamid как первичный ключ?

Вот что-то глупо, я попробовал:

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) 

Но да, это был длинный выстрел ...

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

ответ

2

Это проще, чем вы могли ожидать. Решение ниже примерно эквивалентно приведенному из r-m-n, но более прямолинейно, поскольку оно использует современное декларативное отображение. Нет необходимости в @hybrid_property, вы можете просто наследовать steamid от родительского класса.

# 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) 
+0

Я чувствую, что это решение является «правильным» способом сделать это, поэтому я принял его, но я лично * в конечном итоге воспользуюсь ответом r-m-n, поэтому я чувствовал, что даю ему репутацию +100. Я надеюсь, что это руководство SO ... –

+0

Я не на 100% проясняю рекомендации, но это ваша щедрость, чтобы вы могли потратить ее так, как хотите. Самое главное, что вы награждаете награду вообще, и вы это сделали. Я все еще благодарен за принятие. – Julian

+0

С другой стороны, не могли бы вы объяснить, почему вы ожидаете использовать решение r-m-n? Для меня это кажется самонаказанием ... – Julian

1

это может быть сделано с помощью classical mapping

from sqlalchemy import Column, Integer, Table 
from sqlalchemy.orm import mapper 
from sqlalchemy.ext.hybrid import hybrid_property 


class MyPlayer(Player): 
    def __init__(self, steamid, gold): 
     super().__init__(steamid) 
     self.gold = gold 
     self._steamid = super().steamid 


player = Table('player', Base.metadata, 
    Column('_steamid', Integer, primary_key=True), 
    Column('gold', Integer), 
) 


mapper(MyPlayer, player) 
+1

Это работает, но это сложнее, чем необходимо. Вы можете получить тот же результат с декларативным отображением и без использования '@ hybrid_property'; см. мой ответ. – Julian

+0

Похоже, что я ошибался и 'super(). Steamid' фактически * делает * работу (только не для сеттеров), поэтому я могу просто избавиться от' self._steamid = super(). Steamid' и использовать 'def steamid (self): return super(). steamid' как 'hybrid_property' вместо этого! Я также в конечном итоге использую классическое отображение * anyways * из-за огромного количества несовместимого с ним кода, поэтому спасибо за ответ! :) Я не принимал ваш, так как я чувствую, что другой ответ от @Julian - это более «правильный» способ сделать это, но ваш помог мне на этот раз больше, поэтому я дал вам 100 рецензий. –

+0

На первый взгляд кажется, что вы даже не используете 'hybrid_property' в этом ответе. Это была ошибка? –

Смежные вопросы