2016-07-28 13 views
6

silnik gry zapewnia mnie z Player klasy z steamid własności (pochodzące od C++, jest to tylko prosty przykład na to, co to będzie wyglądać w Pythonie):Użyj właściwości/atrybutu klasy podstawowej jako kolumny tabeli?

I następnie przystąpić do podklasy tej klasy dodając atrybut gold:

# my_plugin.py 

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

teraz muszę przechowywać gracz na gold do bazy danych z odtwarzacza na steamid jako klucza podstawowego w celu identyfikacji odtwarzacza. Jak mogę poinformować SQLAlchemy, aby użył właściwości klasy podstawowej jako steamid jako klucza podstawowego?

Oto coś głupie Próbowałem:

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) 

Ale tak, to był długi strzał ...

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

Odpowiedz

2

Jest prostsze niż możesz się spodziewać. Poniższe rozwiązanie jest w przybliżeniu równoważne temu z r-m-n, ale prostsze, ponieważ wykorzystuje nowoczesne mapowanie deklaratywne. Nie ma potrzeby, aby @hybrid_property po prostu dziedziczyć steamid z klasy nadrzędnej.

# 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

Mam wrażenie, że to rozwiązanie jest "właściwym" sposobem, aby to zrobić, więc zaakceptowałem to, ale * osobiście * skończę, używając odpowiedzi r-m-n, dlatego czułem, że chcę dać mu replikę +100. Mam nadzieję, że jest to zgodne z wytycznymi SO ... –

+0

Nie jestem w 100% jednoznaczny w wytycznych, ale jest to Twoja nagroda, więc możesz wydać, jak chcesz. Najważniejsze jest to, że w ogóle przyznałeś nagrodę, a zrobiłeś to. Wciąż jestem wdzięczny za przyjęcie. – Julian

+0

Zastanawiając się, dlaczego spodziewasz się skorzystać z rozwiązania r-m-n, możesz się zastanowić. Dla mnie to wygląda na samokrytycyzm ... – Julian

1

można to zrobić za pomocą 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

To działa, ale jest bardziej skomplikowane niż to konieczne. Możesz uzyskać ten sam wynik za pomocą deklaratywnego mapowania i bez użycia '@ hybrid_property'; zobacz moją odpowiedź. – Julian

+0

Wygląda na to, że się myliłem i 'super(). Steamid' faktycznie * działa * (tylko dla seterów), więc mogę po prostu pozbyć się' self._steamid = super(). Steamid' i użyć 'def steamid (self): return super(). steamid' zamiast 'hybrid_property' zamiast tego! Skończę też przy użyciu klasycznego mapowania * w każdym razie * ze względu na ogromną ilość niezbyt zgodnego kodu, więc dziękuję za odpowiedź! :) Nie akceptowałem twojego, ponieważ czuję, że inna odpowiedź od @Juliana jest bardziej "prawidłowym" sposobem, ale twój pomógł mi tym razem bardziej, więc dałem ci 100 punktów nagrody. –

+0

Na drugi rzut oka wydaje się, że w tej odpowiedzi nie używasz nawet 'hybrid_property'. Czy to był błąd? –