【问题标题】:User group assignment track in django admindjango admin 中的用户组分配跟踪
【发布时间】:2016-02-10 09:36:11
【问题描述】:

在 Django 中,我想跟踪如何将组分配给用户,现在我们正在通过 Django Admin 将组分配给用户。我尝试在 User.groups.through 表上使用 m2m_changed 信号,但是在 Django 管理员中,当组分配给用户时,它首先清除现有的用户组并添加更新的组,因此它会创建对“pre_clear”和“post_clear”操作的不必要调用信号,因此信号并非在所有情况下都有效。

谁能建议我如何覆盖 Django 用户保存方法并在该方法中处理更改的组?或任何其他方式来跟踪用户组分配?

我正在使用 Django 1.6

【问题讨论】:

  • 我认为你可以展示一些代码,以便其他人更好地理解你,并发布解决方案。

标签: python django


【解决方案1】:

这是 Django 的一个已知问题,仅在 1.9 中修复: https://docs.djangoproject.com/en/1.9/releases/1.9/#related-set-direct-assignment.

ORM 中相关对象的直接赋值,用于执行一个 clear() 之后调用 add()。这导致了不必要的大数据 更改并阻止使用 m2m_changed 信号跟踪个人 多对多关系的变化。

直接赋值现在依赖于相关的新 set() 方法 默认情况下只处理现有之间的更改的管理器 相关集和新分配的集。以前的行为 可以通过调用 set() 替换直接分配来恢复 关键字参数 clear=True。

ModelForm,因此 ModelAdmin,内部依赖于直接 多对多关系的分配,因此现在使用 新行为。

如果您手动使用user.groups.add(foo)user.groups.remove(foo),那么您当前的信号接收器应该可以正常工作。但是 django admin 使用分配,因此它会在 django-admin 的每次保存时清除并设置。要在不更新到 django 1.9 的情况下解决此问题,您必须同时处理 pre_clearpost_add:将清除的 pks 存储到 preclear 中实例的某些“特殊”属性,然后计算添加或删除的内容。

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()

【讨论】:

  • 是的,现在我正在以与您提到的相同的方式处理它,但是当所有组都被删除时,只有 pre_clear 被调用并且 post_add 没有被调用,所以我怎样才能检测到使用这个信号删除了所有组?注意:由于某种原因,我现在无法升级到 1.9。
  • 可能的解决方案是在 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 = removed_pks; ...; instance.change_tracker.save()。这种方式 pre_clear 没有 post_add 也将被跟踪
  • 更新了我的答案,展示了当组完全清除和/或仅添加时如何处理
猜你喜欢
  • 2011-09-25
  • 1970-01-01
  • 2015-03-21
  • 1970-01-01
  • 1970-01-01
  • 2015-12-30
  • 2011-08-31
  • 2010-12-05
  • 1970-01-01
相关资源
最近更新 更多