2014-06-16 56 views

回答

0

我試圖做到這一點,並失敗,因爲SQLAlchemy會話跟蹤對象的狀態。所以沒有簡單的方法讓會話將新對象作爲持久對象來跟蹤。

但是你想將對象重置爲默認值,是嗎?有一個簡單的方法可以做到這一點:

from sqlalchemy.ext.declarative import declarative_base 

class Base(object): 

    def reset(self): 
     for name, column in self.__class__.__table__.columns.items(): 
      if column.default is not None: 
       setattr(self, name, column.default.execute()) 

Base = declarative_base(bind=engine, cls=Base) 

這將reset方法添加到所有模型類。

下面是完整的工作示例亂動:

import os 
from datetime import datetime 


from sqlalchemy import create_engine 
from sqlalchemy import Column, Integer, String, DateTime 
from sqlalchemy.orm import sessionmaker 
from sqlalchemy.ext.declarative import declarative_base 
from sqlalchemy.sql import functions 


here = os.path.abspath(os.path.dirname(__file__)) 
engine = create_engine('sqlite:///%s/db.sqlite' % here, echo=True) 
Session = sessionmaker(bind=engine) 


class Base(object): 

    def reset(self): 
     for name, column in self.__class__.__table__.columns.items(): 
      if column.default is not None: 
       setattr(self, name, column.default.execute()) 

Base = declarative_base(bind=engine, cls=Base) 


class Thing(Base): 
    __tablename__ = 'things' 

    id = Column(Integer, primary_key=True) 
    value = Column(String(255), default='default') 
    ts1 = Column(DateTime, default=datetime.now) 
    ts2 = Column(DateTime, default=functions.now()) 

    def __repr__(self): 
     return '<Thing(id={0.id!r}, value={0.value!r}, ' \ 
       'ts1={0.ts1!r}, ts2={0.ts2!r})>'.format(self) 


if __name__ == '__main__': 
    Base.metadata.drop_all() 
    Base.metadata.create_all() 

    print("---------------------------------------") 
    print("Create a new thing") 
    print("---------------------------------------") 
    session = Session() 
    thing = Thing(
     value='some value', 
     ts1=datetime(2014, 1, 1), 
     ts2=datetime(2014, 2, 2), 
    ) 
    session.add(thing) 
    session.commit() 
    session.close() 

    print("---------------------------------------") 
    print("Quering it from DB") 
    print("---------------------------------------") 
    session = Session() 
    thing = session.query(Thing).filter(Thing.id == 1).one() 
    print(thing) 
    session.close() 

    print("---------------------------------------") 
    print("Reset it to default") 
    print("---------------------------------------") 
    session = Session() 
    thing = session.query(Thing).filter(Thing.id == 1).one() 
    thing.reset() 
    session.commit() 
    session.close() 

    print("---------------------------------------") 
    print("Quering it from DB") 
    print("---------------------------------------") 
    session = Session() 
    thing = session.query(Thing).filter(Thing.id == 1).one() 
    print(thing) 
    session.close() 
+0

這隻適用於具有標量默認值的列。函數,上下文函數和sql表達式都將導致失敗。 – davidism

+0

我更新了我的答案。現在這個例子可以和用戶定義的函數以及服務器端默認一起使用。 –

+0

不幸的是,重置方法並不能解決我的問題。是的,我想重置爲默認值,但通過創建具有默認值的新實例來實現這一點非常重要,並且可以在插入新實例或更新現有值之間進行選擇。 –

0

有沒有什麼簡單的方法來做到這一點?

經過進一步的考慮,並不是真的。最簡潔的方法是在__init__中定義默認值。從DB獲取對象時從不調用構造函數,所以它非常安全。您還可以使用後端功能,例如current_timestamp()

class MyObject(Base): 
    id = Column(sa.Integer, primary_key=True) 
    column1 = Column(sa.String) 
    column2 = Column(sa.Integer) 
    columnN = Column(sa.String) 
    updated = Column(sa.DateTime) 

    def __init__(self, **kwargs): 
     kwargs.setdefault('column1', 'default value') 
     kwargs.setdefault('column2', 123) 
     kwargs.setdefault('columnN', None) 
     kwargs.setdefault('updated', sa.func.current_timestamp()) 
     super(MyObject, self).__init__(**kwargs) 

default_obj = MyObject() 
default_obj.id = old_id 
session.merge(default_obj) 
session.commit() 
+0

你確定嗎?這對我來說根本不起作用。實際上,在提交之後,我保持原始對象不變,就好像沒有任何事情發生一樣。 –

+0

其實我只是注意到我的測試代碼使用__init__來設置一些值,這看起來有很大的不同。合併適用於編輯的值,但不會觸發default()。您始終可以創建一個新實例,複製密鑰,刪除舊的並添加新的實例。 –