Python Django模型类装饰器

Python Django模型类装饰器,python,django,Python,Django,我需要跟踪Django模型实例上的更改。我知道像django回归这样的解决方案,但它们对我的事业来说是杀伤力过大 我想创建一个参数化的类装饰器来满足这个目的。参数是字段名和回调函数。以下是我目前掌握的代码: def audit_fields(fields, callback_fx): def __init__(self, *args, **kwargs): self.__old_init(*args, **kwargs) self.__old_state

我需要跟踪Django模型实例上的更改。我知道像django回归这样的解决方案,但它们对我的事业来说是杀伤力过大

我想创建一个参数化的类装饰器来满足这个目的。参数是字段名和回调函数。以下是我目前掌握的代码:

def audit_fields(fields, callback_fx):
    def __init__(self, *args, **kwargs):
        self.__old_init(*args, **kwargs)
        self.__old_state = self.__get_state_helper()

    def save(self, *args, **kwargs):
        new_state = self.__get_state_helper()

        for k,v in new_state.items():
            if (self.__old_state[k] != v):
                callback_fx(self, k, self.__old_state[k], v)

        val = self.__old_save(*args, **kwargs)
        self.__old_state = self.__get_state_helper()
        return val

    def __get_state_helper(self):
        # make a list of field/values.
        state_dict = dict()
        for k,v in [(field.name, field.value_to_string(self)) for field in self._meta.fields if field.name in fields]:
            state_dict[k] = v
        return state_dict

    def fx(clazz):
        # Stash originals
        clazz.__old_init = clazz.__init__
        clazz.__old_save = clazz.save

        # Override (and add helper)
        clazz.__init__ = __init__
        clazz.__get_state_helper = __get_state_helper
        clazz.save = save
        return clazz

    return fx
并按如下方式使用(仅相关部分):

并在Django壳体上进行以下试验:

from store.models import Order
o=Order()
o.status=Order.OPEN
o.save()
我收到的错误是:

TypeError: int() argument must be a string or a number, not 'Order'
完整的堆栈跟踪如下所示:

提前谢谢,如果您需要更多信息,请告诉我


编辑:问题由randomhuman回答,代码已编辑并可用,如图所示

您不需要在此行上显式传递对self的引用:

val = self.__old_save(self, *args, **kwargs)

它是对对象引用调用的方法。以这种方式显式传递它会导致它被视为save方法的其他参数之一,该参数应为字符串或数字。

的确,randomhuman改变了这一点,但仍然是相同的错误。。。因此,这个问题仍然没有得到回答:(新的
\uuuu init\uuuu
的第一行也有同样的问题,尽管我会认为这个问题与我最初提到的那行有关。堆栈跟踪是否与以前完全相同?显然,在Python shell上重新导入文件不是一个完全刷新…昨晚已经很晚了:-)谢谢你的帮助!是的,如果你只是做了第二次导入,那么它就不会:当你导入一个模块时,它会检查它之前是否导入过,如果它没有任何操作。您必须采取非常措施来执行“重新导入”。不管怎样,很高兴你成功了!回调函数和内部函数都被命名为
fx
,这让人非常困惑。
val = self.__old_save(self, *args, **kwargs)