【问题标题】:Property behaviour (getter and setter) for a column, instead of normal attribute behaviour列的属性行为(getter 和 setter),而不是正常的属性行为
【发布时间】:2016-12-21 16:10:11
【问题描述】:

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、level 和 xp 将存储到数据库中。所以基本上是Column,但不是属性而是属性。

【问题讨论】:

    标签: python python-3.x properties sqlalchemy


    【解决方案1】:

    只需添加一个_xp 列定义,它映射到表中的xp 列,并使用常规@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
    
        @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
    

    见Naming Columns Distinctly from Attribute Names。

    上面将实例上的_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。

    如果你想对你的角色进行批量更新,你可能需要include a update_expression implementation 告诉 SQLAlchemy 如何为UPDATE 生成一个SET 表达式;除了调整 XP 之外,也许还可以使用 CASE 表达式来处理关卡更新。

    【讨论】:

    • 谢谢!仍然希望有一天能看到类似属性的专栏^^
    • 然而,这样的属性不会在现有选项上添加任何内容。
    • 在这种特殊情况下肯定不是,但有时它允许一个人只有属性列,而没有别的。
    • @NamGVU:您将在此处使用Character._xp == 122 作为解决方案。 SQLAlchemy 还提供了hybrid_property,然后它会按照你想要的方式运行。
    • @NamGVU:我已经更新了答案,但需要注意批量更新。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-05
    • 1970-01-01
    相关资源
    最近更新 更多