属性行为(getter和setter)用于列,而不是普通属性行为



SQLAlchemy是否支持这样的操作:

class Character(Base):
   __tablename__ = 'character'
   id = Column(Integer, primary_key=True)
   level = Column(Integer)
   @ColumnProperty(Integer)
   def xp(self):
       return self._xp
   @xp.setter
   def xp(self, value):
       self._xp = value
       while self._xp >= self.xp_to_level_up():
           self.level += 1
           self._xp -= 100
   def __init__(self, level=0, xp=0):
       self.level = level
       self._xp = xp

其中id, levelxp将被存储到数据库中。所以基本上是一个Column,但不是一个属性,而是一个属性。

只需添加一个_xp列定义,它映射到表中的xp列,并使用一个常规的@property对象来实现您的setter逻辑:

class Character(Base):
    __tablename__ = 'character'
    id = Column(Integer, primary_key=True)
    level = Column(Integer)
    _xp = Column('xp', Integer)
    def __init__(self, level=0, xp=0):
        self.level = level
        self._xp = xp
    @property
    def xp(self):
        return self._xp
    @xp.setter
    def xp(self, value):
        self._xp = value
        while self._xp >= self.xp_to_level_up():
            self.level += 1
            self._xp -= 100

参见与属性名区分命名列

上面将实例上的_xp属性存储为character表中的xp,但是您的代码使用Character.xp属性间接地读写_xp的值。

也可以使用@hybrid_property;这就像上面使用的property一样,但也允许您在查询过滤器中使用Character.xp:

from sqlalchemy.ext.hybrid import hybrid_property
class Character(Base):
    __tablename__ = 'character'
    id = Column(Integer, primary_key=True)
    level = Column(Integer)
    _xp = Column('xp', Integer)
    def __init__(self, level=0, xp=0):
        self.level = level
        self._xp = xp
   @hybrid_property
   def xp(self):
        return self._xp
   @xp.setter
   def xp(self, value):
        self._xp = value
        while self._xp >= self.xp_to_level_up():
            self.level += 1
            self._xp -= 100

现在您可以使用session.query(Character).filter(Character.xp > 42)和其他类似的过滤查询,而不必使用Character._xp

如果你想对你的字符进行批量更新,你可能必须包含一个update_expression实现,它将告诉SQLAlchemy如何为UPDATE生成SET表达式;也许使用CASE表达式来处理更新关卡,除了调整XP。

最新更新