Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
193 views
in Technique[技术] by (71.8m points)

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

Recently I figured out that SQLAlchemy's Column default doesn't work as I expect it to:

>>> Base = declarative_base()
>>> class TestModel(Base):
    ... ? ? __tablename__ = 'tmodel'
... ? ? id = sa.Column(sa.Integer, primary_key=True)
... ? ? foo = sa.Column(sa.Integer, default=0)
... ? ?
>>> tmodel_instance = TestModel()
>>> print tmodel_instance.foo
None
>>> session.add(tmodel_instance)
>>> print tmodel_instance.foo
None
>>> session.commit()
>>> print tmodel_instance.foo
0

I want tmodel_instance.foo to equal 0 right after object instantiation, but it seems that the default value is only used when executing INSERT command, and it really confuses me. Why would one prefer the default over server_default? And how do I achieve what I want? Am I supposed to specify all default arguments in __init__? That seems to be code duplication: to change the default value I have to change it twice and maintain those values equality -- is there some way to avoid that?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...