【问题标题】:Assign User-objects to a Group while editing Group-object in Django admin在 Django admin 中编辑组对象时将用户对象分配给组
【发布时间】:2011-08-31 03:09:39
【问题描述】:

在用户对象(编辑用户)的默认 Django 管理视图中,可以编辑用户的组成员资格。如果我也想反过来呢? IE。在群组编辑页面中,可以选择属于正在编辑的群组的用户。

正如我所看到的,Django 没有从 Group 到 User 对象的 ManyToMany 映射,这使得(?)无法为这种特殊情况实现 ModelAdmin 类。如果我可以创建一个额外的 UsersOfGroup 模型类并在 Django 的 Group 模型的 ManyToMany 字段中使用它作为直通属性,那么可能会有一种方法。

任何想法,这是否可以使用 ModelAdmin 技巧来实现,还是我只需要为编辑组制作自定义视图?

我已经检查了另外两个问题,但它们的作用并不完全相同:

Assigning a group while adding user in admin

Show group membership in admin

更新: 克里斯的回答几乎就在那里。 :) 该组引用了用户集,但它被称为 user_set,而不是 users。以下是我所做的更改:

if self.instance and self.instance.pk:
    self.fields['users'].initial = self.instance.user_set.all()

if group.pk:
    group.user_set = self.cleaned_data['users']

【问题讨论】:

    标签: django django-admin membership usergroups


    【解决方案1】:

    如果您添加一个新组并同时将用户添加到该组,上述保存方法将不起作用。问题是新组不会被保存(管理员使用 commit=False)并且没有主键。由于 save_m2m() 的目的是允许调用视图处理保存 m2m 对象,因此我制作了一个保存对象,它将旧的 save_m2m 方法包装在一个新方法中。

    def save(self, commit=True):
        group = super(GroupAdminForm, self).save(commit=commit)
    
        if commit:
            group.user_set = self.cleaned_data['users']
        else:
            old_save_m2m = self.save_m2m
            def new_save_m2m():
                old_save_m2m()
                group.user_set = self.cleaned_data['users']
            self.save_m2m = new_save_m2m
        return group
    

    【讨论】:

    • 我可以确认这是处理 M2M 关系的正确方法。
    【解决方案2】:

    yourapp/admin.py

    from django import forms
    from django.contrib import admin
    from django.utils.translation import ugettext_lazy as _
    from django.contrib.admin.widgets import FilteredSelectMultiple
    
    from django.contrib.auth.models import User, Group
    
    class GroupAdminForm(forms.ModelForm):
        users = forms.ModelMultipleChoiceField(
            queryset=User.objects.all(), 
            required=False,
            widget=FilteredSelectMultiple(
                verbose_name=_('Users'),
                is_stacked=False
            )
        )
    
        class Meta:
            model = Group
    
        def __init__(self, *args, **kwargs):
            super(GroupAdminForm, self).__init__(*args, **kwargs)
    
            if self.instance and self.instance.pk:
                self.fields['users'].initial = self.instance.users.all()
    
        def save(self, commit=True):
            group = super(GroupAdminForm, self).save(commit=False)
    
            if commit:
                group.save()
    
            if group.pk:
                group.users = self.cleaned_data['users']
                self.save_m2m()
    
            return group
    
    class GroupAdmin(admin.ModelAdmin):
        form = GroupAdminForm
    
    admin.site.unregister(Group)
    admin.site.register(Group, GroupAdmin)
    

    【讨论】:

    • 谢谢,这成功了!我不得不对其进行一些编辑,但基本上这就是解决方案。
    • 上面的代码对我有用。我唯一需要做的就是将 self.instance.users.all() 更改为 self.instance.user_set.all()
    • 此代码不起作用,因为当您将用户添加到组并保存时,您的更改会被保存。下面tomka 的解决方案适用于最近的 Django 和 Python
    【解决方案3】:

    我在 Django 2.1 上使用 Chris 发布的解决方案,但就像 Cedric 解释的那样,当添加新组并同时将用户添加到新组时,它不起作用。不幸的是,他的代码也没有帮助,但我可以使用下面这个修改后的版本让它工作。

    编辑:我包含了用户am70的建议(谢谢!)并使用了get_user_model()。此代码继续适用于 Django 3.1,并已在 Python 3.6、3.7 和 3.8 上进行了测试。

    from django import forms
    from django.contrib import admin
    from django.utils.translation import ugettext_lazy as _
    from django.contrib.admin.widgets import FilteredSelectMultiple
    from django.contrib.auth import get_user_model ; User = get_user_model()
    from django.contrib.auth.models import Group
    
    class GroupAdminForm(forms.ModelForm):
        users = forms.ModelMultipleChoiceField(
            queryset=User.objects.all(), 
            required=False,
            widget=FilteredSelectMultiple(
                verbose_name=_('Users'),
                is_stacked=False
            )
        )
    
        class Meta:
            model = Group
    
        def __init__(self, *args, **kwargs):
            super(GroupAdminForm, self).__init__(*args, **kwargs)
    
            if self.instance and self.instance.pk:
                self.fields['users'].initial = self.instance.users.all()
    
    
    class GroupAdmin(admin.ModelAdmin):
        form = GroupAdminForm
    
        def save_model(self, request, obj, form, change):
            super(GroupAdmin, self).save_model(request, obj, form, change)
            if 'users' in form.cleaned_data:
                form.instance.user_set.set(form.cleaned_data['users'])
    
    
    admin.site.unregister(Group)
    admin.site.register(Group, GroupAdmin)
    

    【讨论】:

    • 这是唯一一个在 django 3 中工作的 AFAICT。另外我建议不要导入 User 而是导入 from django.contrib.auth import get_user_model ; User = get_user_model()
    • 这是个好建议,谢谢。我将其包含在答案中。
    【解决方案4】:

    这是一种使用 Django 的 InlineModelAdmin 对象 (answered here on Qubanshi.cc) 的更简单的方法

    from django.contrib.auth.admin import GroupAdmin
    from django.contrib.auth.models import User, Group
    
    class UserSetInline(admin.TabularInline):
        model = User.groups.through
        raw_id_fields = ('user',)  # optional, if you have too many users
    
    class MyGroupAdmin(GroupAdmin):
        inlines = [UserSetInline]
    
    # unregister and register again
    admin.site.unregister(Group)
    admin.site.register(Group, MyGroupAdmin)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-22
      • 2017-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-06
      相关资源
      最近更新 更多