SQLAlchemy:使用新的替换对象,遵循默认值

时间:2014-06-16 22:02:33

标签: sqlalchemy

我想创建一个SQLAlchemy对象的新实例,以便字段填充默认值,但我想将其提交给数据库,生成UPDATE到已存在且具有相同主数据的行键,有效地将其重置为默认值。有没有简单的方法呢?

2 个答案:

答案 0 :(得分: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()

答案 1 :(得分: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()