我有一个声明式模型:
class User(Base):
id = Column(Integer, primary_key=True)
money = Column(Integer, default=100)
然后我跑
>>> u = User()
>>> u.money
None
如何在不向数据库写入任何内容的情况下使用 sqlalchemy 填充默认值?
我有一个声明式模型:
class User(Base):
id = Column(Integer, primary_key=True)
money = Column(Integer, default=100)
然后我跑
>>> u = User()
>>> u.money
None
如何在不向数据库写入任何内容的情况下使用 sqlalchemy 填充默认值?
.flush()
列默认值仅适用于 INSERT 和 UPDATE 语句,因此在会话之前不会应用。
要在刷新之前在新实例上看到相同的值,您需要在创建新实例时应用默认值;在对象的__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'
不是Python 布尔对象。False
True
我发现了一种在创建实例时自动填充一些默认值的机制。我正在从在实例创建时设置默认值的内部 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
不支持但也不支持的情况。
由于我不一定在构造函数中需要默认值,但有时来自其他地方,我想出了一个函数,我将它添加到我的基 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)
这显然不适用于可调用对象。我不知道怎么称呼它,也许它是为了更好(感觉就像已经在破解这个想法了)。
有了这个,我可以做类似的事情:
class User(ItemBase):
# ... inheritance, columns and stuff
def __init__(self):
self._ensure_defaults()
我也可以调用 not in 中的方法__init__
,也可以调用其他方法,以防我只需要在特殊情况下依赖这些值(后来我最终将其删除,因为它太混乱了)。在某些情况下,这可能比@JamesEmerton 的解决方案更灵活。