views:

291

answers:

1

I have a situation where I need to notify some users when something in DB changes. My idea is to catch pre_save and post_save signal and make some kind of diff and mail that. Generally it works good, but I don't know how to get diff for m2m fields.

At the moment I have something like this:

def pre_save(sender, **kwargs):
    pk = kwargs['instance'].pk
    instance = copy.deepcopy(sender.objects.get(pk=pk))
    tracking[sender] = instance

def post_save(sender, **kwargs):
    instance = copy.deepcopy(kwargs['instance'])
    print diff(instance, (tracking[sender])) # TODO: don't print, save diff somewhere

Diff function should work for every model (at the mommet I have four model classes). With deepcopy I can save old model, but I don't know how to save m2m fields because they are in separate table (yes, I know I can get this data, but at the momment of execution I don't know what fields are m2m and I wouldn't like to create different slot for every model). What I would like is generic solution, so I can just add models later without thinking about notification part.

My plan is to call get_data() and clear_data() functions after save() in view to clean diff that slots have generated.

Is this good way of doing this? Is there a better way? Is there django application that can do this job for me?

Excuse my English, it's not my native language.

+1  A: 

First of all, you don't need to use deepcopy for this. Re-querying the sender from the database returns a "fresh" object.

def pre_save(sender, **kwargs):
    pk = kwargs['instance'].pk
    instance = sender.objects.get(pk=pk)
    tracking[sender] = instance

You can get a list of all the many-to-many fields for a class, and check the values related to the current instance:

for field in sender._meta.local_many:
    values = field.value_from_object(instance).objects.all()
    # Now values is a list of related objects, which you can diff
Christian Oudard