我需要跟踪Django模型实例的更改。我知道像django-reversion这样的解决方案,但它们对我的事业来说太过分了。
我有想法创建一个参数化的类装饰器来适应这个目的。参数是字段名称和回调函数。这是我目前的代码:
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
并按如下方式使用(仅限相关部分):
@audit_fields(["status"], fx)
class Order(models.Model):
BASKET = "BASKET"
OPEN = "OPEN"
PAID = "PAID"
SHIPPED = "SHIPPED"
CANCELED = "CANCELED"
ORDER_STATES = ( (BASKET, 'BASKET'),
(OPEN, 'OPEN'),
(PAID, 'PAID'),
(SHIPPED, 'SHIPPED'),
(CANCELED, 'CANCELED') )
status = models.CharField(max_length=16, choices=ORDER_STATES, default=BASKET)
使用以下方法测试Django shell:
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'
完整的堆栈跟踪在这里:https://gist.github.com/4020212
提前致谢,如果您需要更多信息,请与我们联系!
编辑:通过randomhuman回答的问题,代码已编辑并可用,如图所示!
答案 0 :(得分:5)
您不需要在此行显式传递对 self 的引用:
val = self.__old_save(self, *args, **kwargs)
这是一个在对象引用上调用的方法。以这种方式显式传递它会使它被视为save方法的其他参数之一,预期是一个字符串或数字。