Why isn't SQLAlchemy default column value available before object is committed? Why isn't SQLAlchemy default column value available before object is committed? python python

Why isn't SQLAlchemy default column value available before object is committed?


one would prefer default over server default for one of four reasons:

  1. 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).

  2. 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.

  3. the SQL expression you want to run isn't supported by the database as a "server default".

  4. 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:

  1. use __init__(). It's python!

  2. 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)