2011-01-20 8 views
5

Я хотел бы отслеживать, какое поле изменилось на любой модели (то есть аудит на уровне модели, поскольку он более атомный, не на уровне администратора/формы, как то, что django и django-reversion уже могут сделать). Я могу сделать это для любого поля, используя сигналы pre/post save/delete. Однако у меня есть проблема с этим в поле m2m.Django: не удается обнаружить изменения в поле «много ко многим» с сигналом m2m_changed - аудит на уровне модели

В приведенном ниже примере кода я определяю поле m2m2 custom_groups в форме изменения пользователя, так как это обратное отношение. Например, когда пользователь сохраняет форму в интерфейсе администратора, я хотел бы войти в журнал, если в поле «custom_groups» есть изменение.

Модель:

from django.contrib.auth.models import User 

class CustomGroup(models.Model): 
    users = models.ManyToManyField(User, related_name='custom_groups') 

ModelForm:

class CustomUserChangeForm(UserChangeForm): 
    custom_groups = forms.ModelMultipleChoiceField(required=False, queryset=CustomGroup.objects.all()) 

Проблема с использованием m2m_changed сигнала является то, что я не могу проверить, что на самом деле изменилось для случая, когда поле M2M обновляется с использованием оператора присваивания:

user.custom_groups = self.cleaned_data['custom_groups'] 

Это связано с тем, что внутреннее django будет выполнять clear() on * custom_groups *, прежде чем вручную добавить все объекты. Это выполнит pre/post-clear, а затем pre/post save в поле m2m.

Я делаю все это неправильно? Есть ли более простой метод, который может действительно работать?

Спасибо!

+0

Это мое решение http://stackoverflow.com/questions/1221878/why-does-django-post-save-signal-give-me-pre-save-data/9172783#9172783 – Fatih

ответ

12

У меня была аналогичная проблема, и я думаю, что смогу ее решить. Я не знаю, как вы используете m2m_changed, но это должно быть на models.py и должны быть похожи на что-то вроде этого:

signals.m2m_changed.connect(your_function, sender=CustomGroup.users.through) 

Теперь, я хотел бы создать файл signals.py, содержащий эту функцию, и следующий код должен напечатать выбранные вами параметры:

def your_function(sender, instance, action, reverse, model, pk_set, **kwargs): 
    if action == 'post_add': 
     for val in pk_set: 
      print val 

Теперь вы знаете обновленные значения. Надеюсь, это может решить вашу проблему.