[英]How to apply Column defaults before a commit in sqlalchemy
我有一个声明基础模型:
class User(Base):
id = Column(Integer, primary_key=True)
money = Column(Integer, default=100)
然后我跑了
>>> u = User()
>>> u.money
None
如何在不向数据库写入任何内容的情况下使用sqlalchemy填充默认值?
列默认仅适用于INSERT和UPDATE语句,因此直到您.flush()
会话.flush()
应用。
要在刷新之前在新实例上看到相同的值,您需要在创建新实例时应用默认值; 在User
对象的__init__
方法中:
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'
字符串值,而不是False
或True
Python布尔对象。
我发现了一种在创建实例时自动填充某些默认值的机制。 我正在从内部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)
这显然不适用于callables。 我无法弄清楚如何调用它,也许它会变得更好(感觉就像已经破解了想法)。
有了这个,我可以这样做:
class User(ItemBase):
# ... inheritance, columns and stuff
def __init__(self):
self._ensure_defaults()
我也可以调用不在__init__
的方法,也可以调用其他方法,以防我在特殊情况下只需依赖值(后来我最终删除了,因为它太混乱了)。 在某些情况下,这可能比@JamesEmerton的解决方案更灵活。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.