如何在sqlalchemy中提交之前应用列默认值

时间:2012-12-09 20:29:52

标签: python sqlalchemy

我有一个声明基础模型:

class User(Base):
    id = Column(Integer, primary_key=True)
    money = Column(Integer, default=100)

然后我跑

>>> u = User()
>>> u.money
None

如何使用sqlalchemy 填充默认值,而无需向数据库写入任何内容?

3 个答案:

答案 0 :(得分:17)

列默认仅适用于INSERT和UPDATE语句,因此在您.flush()会话之前不会应用。

要在刷新之前在新实例上看到相同的值,您需要在创建新实例时应用默认值;在__init__对象的User方法中:

class User(Base):
    __tablename__ = 'users'

    def __init__(self, **kwargs):
        if 'money' not in kwargs:
             kwargs['money'] = self.__table__.c.money.default.arg
        super(User, self).__init__(**kwargs)

    id = Column(Integer, primary_key=True)
    money = Column(Integer, default=100)

如果没有设置money属性,我们会根据为该列配置的默认值直接添加一个属性。

请注意,默认值是 SQL表达式,而不是Python值,因此您可能必须先将这些值映射到Python对象。例如,布尔字段将具有默认的'false''true'字符串值,而不是FalseTrue Python布尔对象。

答案 1 :(得分:7)

我发现了一种在创建实例时自动填充某些默认值的机制。我正在从内部ORM迁移,在设置实例时设置默认值,因此我需要保留此行为,并且我不想触及每个模型定义。

BaseModel = declarative_base()

class Base(BaseModel):
    __abstract__ = True

    def __init__(self, **kwargs):
        for attr in self.__mapper__.column_attrs:
            if attr.key in kwargs:
                continue

            # TODO: Support more than one value in columns?
            assert len(attr.columns) == 1
            col = attr.columns[0]

            if col.default and not callable(col.default.arg):
                kwargs[attr.key] = col.default.arg

        super(Base, self).__init__(**kwargs)

主要限制是仅支持不可调用的默认值。可调用默认值和使用数据库查询的默认值需要在实例创建时不可用的执行上下文。另外,我还没有发现len(ColumnProperty.columns) != 1但不支持的情况。

答案 2 :(得分:1)

由于我不一定需要构造函数中的默认值,但有时需要来自其他地方,我想出了一个函数,我将其添加到我的基类Object类中:

Base = declarative_base()
class ItemBase(Base):
    __abstract__ = True
    def _ensure_defaults(self):
        for column in self.__table__.c:
            if getattr(self, column.name) is None and column.default is not None and column.default.is_scalar:
                setattr(self, column.name, column.default.arg)

这显然不适用于callables。我无法弄清楚如何调用它,也许它会变得更好(感觉就像是已经破解了想法)。

有了这个,我可以这样做:

class User(ItemBase):
    # ... inheritance, columns and stuff
    def __init__(self):
        self._ensure_defaults()

我也可以调用不在__init__中的方法,也可以调用其他方法,以防我在特殊情况下只需要依赖值(后来我最终删除了,因为它太混乱了) 。在某些情况下,这可能比@JamesEmerton的解决方案更灵活。