SQLAlchemy:排除被腌制的列

时间:2016-09-18 22:18:12

标签: sqlalchemy pickle

是否有可能在SQLAlchemy中将列标记为do-not-pickle,以便在取消对其进行unickled后从数据库中按需加载?

这可以通过 <script src="https://code.jquery.com/jquery-2.2.4.min.js"></script> <div class="clickMe"> </div>列部分实现,但如果随后加载了该列,它也会被腌制。

(由于内置的​​deferred具有不可挽回的特性,因此看起来在Python2.7中仍然存在使用酸洗Geoalchemy2 Geometry列的问题:{{3} })

2 个答案:

答案 0 :(得分:0)

这是一个天真的__getstate__实施,但不会有效,但有希望提示正确答案:

Base = declarative_base(metadata=route_metadata)

cols_to_omit = ['my_col_1']

class MyClass(Base):

    my_col_0 = Column(Integer)
    my_col_1 = Column(Integer)

    def __getstate__(self):
        return dict((c, getattr(self, c)) for c in \
              self.__table__.columns.keys() \
              if c not in cols_to_omit)

    def __setstate__(self, *args):
        for c, v in args[0].items():
            setattr(self, c, v)


from pickle import *
pp = dumps(MyClass.query.first())
obj = loads(pp)

这会给AttributeError: 'MyClass' object has no attribute '_sa_instance_state'

答案 1 :(得分:0)

这有点牵扯,因为你不能阻止对某个列进行腌制,因为控制延迟加载的内容实际上在_sa_instance_state属性中,所以即使你没有腌制实例字典中的某些属性SQLAlchemy不知道这意味着它已过期。

一个(稍微hacky)解决方案是在你unpickle时使属性失效:

class Foo(Base):
    __tablename__ = "foo"

    id = Column(Integer, primary_key=True)
    foo = Column(String)
    bar = Column(String)

    def __getstate__(self):
        return {k: v for k, v in self.__dict__.items() if k != "bar"}

    def __setstate__(self, d):
        for k, v in d.items():
            self.__dict__[k] = v
        self._sa_instance_state._expire_attributes(self.__dict__, ("bar",))

请注意,unpickling的结果是一个分离的实例,因此您需要小心使用它:

foo = session.query(Foo).first()
foo = pickle.loads(pickle.dumps(foo))
print(foo.foo)  # fine
# print(foo.bar)  # sqlalchemy.orm.exc.DetachedInstanceError
foo = session.merge(foo, load=False)
print(foo.foo)  # no query
print(foo.bar)  # causes a query