36

最近、SQLAlchemyの列のデフォルトが期待どおりに機能しないことがわかりました。

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

オブジェクトのインスタンス化の直後tmodel_instance.fooに等しくしたいのですが、デフォルト値はコマンドを実行するときにのみ使用されるようで、本当に混乱します。なぜ人はよりも好むのでしょう か?そして、どうすれば私が望むものを達成できますか?すべてのデフォルト引数をで指定することになっていますか?これはコードの重複のようです。デフォルト値を変更するには、2回変更して、それらの値を等しく維持する必要があります。これを回避する方法はありますか?0INSERTdefaultserver_default__init__

4

3 に答える 3

26

次の4つの理由のいずれかにより、サーバーのデフォルトよりもデフォルトを優先します。

  1. デフォルトでは、SQL関数ではなくPython関数を実行したいとします(または、INSERTごとのPython状態も必要とするSQL式)。

  2. デフォルトは主キー列の一部です。ORMは主キーがないと行を読み戻すことができないため、ORMを使用する場合、server_defaultは通常PK列には役立ちません。

  3. 実行するSQL式は、「サーバーのデフォルト」としてデータベースでサポートされていません。

  4. 変更できない/変更したくないスキーマを扱っています。

この場合、データベース操作とは関係なく、アプリケーションで「foo」を「0」にしたい場合は、次の選択肢があります。

  1. を使用します__init__()。Pythonです!

  2. イベントを使用します。

ここにあり__init__()ます:

class TestModel(Base):
   # ...

   def __init__(self):
       self.foo = 0

イベント(具体的にはinitイベント)は次のとおりです。

from sqlalchemy import event

@event.listens_for(Foo, "init")
def init(target, args, kwargs):
    target.foo = 0
于 2012-12-23T17:35:45.483 に答える
11

force_instant_defaultsリスナーfromを使用しsqlalchemy_utilsて、この動作を変更できます。

from sqlalchemy_utils import force_instant_defaults

force_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
于 2018-01-04T14:40:32.533 に答える
6

イベントを使用してinitデフォルトを埋めることができます。このイベントリスナーはそれを行います:

from sqlalchemy import event
from sqlalchemy.orm import mapper
from sqlalchemy.inspection import inspect


def 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)
于 2014-07-22T16:46:28.270 に答える