SQLAlchemy:声明性MIXIN类中的getter/setter

10 投票
2 回答
7494 浏览
提问于 2025-04-16 16:36

我正在尝试为一个混合类定义简单的获取器和设置器方法,这个类我打算用在我的数据库结构中:

from sqlalchemy import Column, Integer, create_engine
from sqlalchemy.orm import synonym, scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base, declared_attr

engine = create_engine('sqlite:///')
Base = declarative_base(bind=engine)
Session = scoped_session(sessionmaker(bind=engine))


class Mixin(object):
    _attr = Column('attr', Integer)

    @property
    def attr(self):
        return self._attr

    @attr.setter
    def attr(self, value):
        self._attr = value

    attr = synonym('_attr', descriptor=attr)


class DummyClass(Base, Mixin):
    __tablename__ = 'dummy'

    id = Column(Integer, primary_key=True)

Base.metadata.create_all()

if __name__ == '__main__':
    session = Session()
    testobj = DummyClass()
    session.add(testobj)
    testobj.attr = 42
    assert testobj.attr == 42

当我尝试运行这个例子时,出现了以下错误:

sqlalchemy.exc.InvalidRequestError: 映射器属性(比如 deferred、column_property()、relationship() 等)必须在声明性混合类中作为 @declared_attr 可调用对象来声明。

我的代码几乎是从 SQLAlchemy 声明式教程 复制过来的,唯一的不同是这个属性/同义词是在一个混合类中声明的。把 "@declared_attr" 装饰器加到现有的装饰器前面或后面并没有改变任何东西。

我该如何解决这个问题呢?

2 个回答

-1
@contact.setter
def contact_id(self, contact_id):
    if (contact_id is None):
        raise ValueError('contact_id can only be a uuid string')

    if not isinstance(contact_id, str):
        raise TypeError('contact_id is not a string')

    self._contact_id = contact_id

使用一个设置器,上面的代码可以抛出比PyAlchemy更清晰的错误信息。

如果可以的话,你也可以选择在生产环境中优雅地处理这个错误。

14

也许可以把 attr() 创建成一个用 @declared_attr 装饰的类方法,这样它就可以返回一个同义词了?

class Mixin(object):

    _attr = Column('attr', Integer)

    def get_attr(self):
        return self._attr

    def set_attr(self, value):
         self._attr = value

    @declared_attr
    def attr(cls):
        return synonym('_attr', descriptor=property(cls.get_attr, cls.set_attr))

撰写回答