如何在SQLAlchemy中防止特定类别被更新/删除?

4

假设我有三个类:Dog()、Walrus()、Boot()。 我想让Walrus对象无法更新,但可以删除;同时,你永远无法删除Boot对象。 因此,如果我执行以下操作:

dog1 = Dog("DogName")
walrus1 = Walrus("WalrusName")
boot1 = Boot("BootName")
session.add(dog1)
session.add(walrus1)
session.add(boot1)
session.flush()
transaction.commit()
dog1.name = "Fluffy"
walrus1.name = "Josh"
boot1.name = "Pogo"
session.flush()
transaction.commit()

更改海象名称将引发异常,但允许更改其他名称。如果我尝试删除boot1,它将引发异常。

我尝试了几种事件侦听器的方法,但我的方法都无法解决问题:

#One possibility
#I don't know how to tell that it's just an update though
#The is_modified seems to take inserts as well

@event.listens_for(Session, 'before_flush')
def listener(thissession, flush_context, instances):
    for obj in thissession:
        if isinstance(obj, Walrus):
            if thissession.is_modified(obj, include_collections=False):
                thissession.expunge(obj)


#Possiblity two
#It says before_update but it seems to take in inserts as well
#Also documentation says it's not completely reliable to capture all statements
#where an update will occur
@event.listens_for(Walrus, 'before_update', raw=True)
def pleasework(mapper, connection, target):
    print "\n\nInstance %s being updated\n\n" % target
    object_session(target).expunge(target)

编辑1:

@event.listens_for(Walrus, 'before_update', raw=True)
def prevent_walrus_update(mapper, connection, target):
    print "\n\nInstance %s being updated\n\n" % target
    if target not None:
        raise

@event.listens_for(Boot, 'before_delete', raw=True)
def prevent_boot_delete(mapper, connection, target):
    print "\n\nInstance %s being deleted\n\n" % target
    if target not None:
        raise

我已经让它可以防止我更新Walrus或删除Boot,但任何尝试都会导致AttributeError的崩溃,我似乎没有能力捕捉到它。例如,如果我运行Walrus1.name = "Josh",然后进行任何查询,甚至是get,AttributeError都会导致应用程序崩溃。我比之前更进一步了,但仍然非常不方便。

1个回答

1
第一个解决方案看起来应该可以工作,如果你只是改变循环的读取方式:
for obj in thissession.dirty:

您可以使用相同的before_flush事件,通过循环遍历thissession.deleted来防止删除Boot对象。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接