Why isn't SQLAlchemy default column value available before object is committed?
one would prefer default over server default for one of four reasons:
you'd like to run a Python function, not a SQL function, for the default (or a SQL expression that needs some per-INSERT Python state also).
the default is part of a primary key column. the ORM can't load a row back without the primary key, so server_default is generally not useful for a PK column when using the ORM.
the SQL expression you want to run isn't supported by the database as a "server default".
You're dealing with a schema you can't/don't want to change.
In this case, when you'd like "foo" to be "0" in your application independent of database operations, the choices are:
use
__init__()
. It's python!use events.
Here's __init__()
:
class TestModel(Base): # ... def __init__(self): self.foo = 0
Here's events (specifically the init event):
from sqlalchemy import event@event.listens_for(Foo, "init")def init(target, args, kwargs): target.foo = 0
You can use force_instant_defaults
listener from sqlalchemy_utils
to change this behavior:
from sqlalchemy_utils import force_instant_defaultsforce_instant_defaults()class TestModel(Base): __tablename__ = 'tmodel' id = sa.Column(sa.Integer, primary_key=True) foo = sa.Column(sa.Integer, default=0)model = TestModel()assert model.foo == 0
You can use the init
event to fill defaults. This event listener will do it:
from sqlalchemy import eventfrom sqlalchemy.orm import mapperfrom sqlalchemy.inspection import inspectdef instant_defaults_listener(target, args, kwargs): for key, column in inspect(target.__class__).columns.items(): if column.default is not None: if callable(column.default.arg): setattr(target, key, column.default.arg(target)) else: setattr(target, key, column.default.arg)event.listen(mapper, 'init', instant_defaults_listener)