2016-02-10 3 views
9

В Django Я хочу отслеживать, как группы назначены пользователю, прямо сейчас мы назначаем группу пользователю через Django Admin. Я попытался использовать сигнал m2m_changed в таблице User.groups.through, но в администраторе Django, когда группа назначена пользователю, тогда она сначала очищает существующие группы пользователей и добавляет обновленные группы, поэтому создает ненужный вызов действий «pre_clear» и «post_clear» так что из-за этого сигнал не работает во всех случаях.Отслеживание заданий группы пользователей в django admin

Может ли кто-нибудь предложить мне способ переопределить метод сохранения пользователя Django и обработать измененную группу в этом методе? или каким-либо другим способом отслеживать назначение групп пользователей?

Я использую Django 1.6

+0

Я думаю, вы могли бы показать какой-то код, чтобы другие могли лучше понять вас и опубликовать решение. – pktangyue

ответ

5

Это известная проблема Джанго и она была установлена ​​только в версии 1.9: https://docs.djangoproject.com/en/1.9/releases/1.9/#related-set-direct-assignment.

Прямое присвоение связанных объектов в ORM, используемых для выполнения операции clear(), за которым следует вызов для добавления(). Это вызвало ненужные большие данные изменений и предотвратило использование сигнала m2m_changed для отслеживания отдельных изменений во многих отношениях.

Прямое присвоение теперь основано на новом методе set() для связанных менеджеров , который по умолчанию обрабатывает только изменения существующего связанного набора и того, который был недавно назначен. Предыдущее поведение может быть восстановлено путем замены прямого назначения вызовом set() с аргументом ключевого слова clear = True.

ModelForm, и поэтому ModelAdmin, внутренне полагаются на прямое назначение для отношений «многие ко многим» и, как следствие, теперь используют новое поведение .

Если вы вручную использовали user.groups.add(foo) или user.groups.remove(foo), то ваш приемник текущего сигнала должен работать нормально. Но администратор django использует назначение, поэтому он становится понятным и устанавливается при каждом сохранении из django-admin. Чтобы исправить эту проблему без обновления django 1.9, вам необходимо обработать как pre_clear, так и post_add: сохраните очищенный pks до некоторого «специального» атрибута экземпляра в преклирете, а затем вычислите, что было добавлено или удалено.

def pre_clear_handler(sender, *args, **kwargs): 
    # ... 
    instance._cleared_groups_pk_set = set([group.pk for group in instance.groups.all()]) # or `set(instance.groups.all().values_list('pk', flat=True)) 
    tracker = SomeTrackingModel() 
    tracker.removed_group_ids = instance._cleared_groups_pk_set 
    tracker.save() # post_add may not be called if groups are fully cleared 
    instance._changes_tracker_helper = tracker 

def post_add_handler(sender, *args, **kwargs): 
    # ... 
    prev_groups_pk_set = getattr(instance, '_cleared_groups_pk_set', None) 
    if prev_groups_pk_set is not None: 
     not_realy_added_pk_set = kwargs['pk_set'] 
     removed_pks = prev_groups_pk_set - not_realy_added_pk_set 
     realy_added_pks = not_realy_added_pk_set - prev_groups_pk_set 
    else: 
     removed_pks = set() 
     realy_added_pks = kwargs['pk_set'] 
    tracker = getattr(instance, '_changes_tracker_helper', SomeTrackingModel()) 
    tracker.removed_group_ids = removed_pks 
    tracker.added_group_ids = realy_added_pks 
    tracker.save() 
+0

Да, прямо сейчас я обрабатываю его так же, как вы упомянули, но когда все группы удалены, тогда вызываются только pre_clear и post_add, поэтому как я могу обнаружить, что все группы удаляются с использованием этих сигналов? Примечание: по какой-то причине я не могу перейти на 1.9 сейчас. – Yogesh

+0

возможным решением было бы сохранить изменения в pre_clear и отслеживать «объект изменения» в экземпляре ('...; tracker.removed_group_ids = instance._cleared_groups_pk_set; tracker.save(); instance.change_tracker = tracker'). и в post_add: верните или измените отслеживаемые изменения, чтобы исправить их и сохранить снова ('instance.change_tracker.removed_group_ids = deleted_pks; ...; instance.change_tracker.save()'. Таким образом, pre_clear без post_add будет отслеживаться слишком – imposeren

+0

обновил мои ответ, чтобы показать, как обращаться, когда группы полностью очищены и/или добавлены только – imposeren