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

Elr*_*ond 18 python sqlalchemy

我有一个声明基础模型:

class User(Base):
    id = Column(Integer, primary_key=True)
    money = Column(Integer, default=100)
Run Code Online (Sandbox Code Playgroud)

然后我跑了

>>> u = User()
>>> u.money
None
Run Code Online (Sandbox Code Playgroud)

如何在向数据库写入任何内容的情况下使用sqlalchemy填充默认值?

Mar*_*ers 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)
Run Code Online (Sandbox Code Playgroud)

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

请注意,默认值是SQL表达式,而不是Python值,因此您可能必须首先将它们映射到Python对象.例如,一个布尔字段将具有默认'false''true'字符串值,而不是一个FalseTruePython的布尔对象.

  • 因此,如果我想填写更复杂对象的所有默认值,我必须迭代所有列,看它是否有默认值并将其填充到相应的属性中.好的,我可以编写代码.我只是想知道:这个功能必须存在于sqlalchemy中,因为无论如何它在插入/更新时都需要它.我想知道,为什么它不会暴露给用户. (2认同)
  • 我喜欢Martijn的解决方案,看起来非常完整.我过去总是像这样做,这可能会少一点代码,因为你不必迭代你的列.http://stackoverflow.com/questions/13384996/how-do-i-set-attribute-default-values-in-sqlalchemy-declarative/13390300#13390300 (2认同)

Jam*_*ton 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)
Run Code Online (Sandbox Code Playgroud)

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