3

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シェルで次のようにテストします。

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

よろしくお願いします。さらに情報が必要な場合はお知らせください。

編集:ランダムヒューマンによって回答された質問、コードは編集され、示されているように使用可能です!

4

1 に答える 1

5

この行で自分自身への参照を明示的に渡す必要はありません。

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

これは、オブジェクト参照で呼び出されるメソッドです。この方法で明示的に渡すと、saveメソッドの他のパラメーターの1つと見なされ、文字列または数値であることが期待されます。

于 2012-11-05T21:38:26.167 に答える