在 Django 管理中编辑组对象时将用户对象分配给组

发布于 2024-11-09 08:07:30 字数 973 浏览 0 评论 0原文

在用户对象(编辑用户)的默认 Django 管理视图中,可以编辑用户的组成员身份。如果我也想反过来怎么办?即,在组编辑页面中,可以选择属于正在编辑的组的用户。

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

有什么想法吗?这是否可以使用 ModelAdmin 技巧来实现,或者我只需要为编辑组创建自定义视图?

我已经检查了另外两个问题,但它们并没有完全做同样的事情:

在管理中添加用户时分配组

在管理中显示组成员身份

更新: 克里斯的答案差不多就到了。 :) 该组有一个对用户集的引用,但它被称为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']

In the default Django admin view for user-object (edit user) one can edit the user's group memberships. What if I wanted this the other way around also? I.e. in the group editing page one could select the users that belong to the group being edited.

As I see this, Django doesn't have a ManyToMany mapping from Group to User object which makes it impossible(?) to implement a ModelAdmin class for this particular case. If I could make an additional UsersOfGroup model class and use it in the Django's Group model's ManyToMany field as a through-attribute, there could be a way.

Any ideas, is this possible to implement using ModelAdmin tricks or do I just have to make a custom view for editing groups?

I have checked these two other questions, but they don't quite do the same thing:

Assigning a group while adding user in admin

and

Show group membership in admin

Updated:
The answer from Chris was almost there. :) The group has a reference to the users set, but it's called user_set, not users. So these are the changes I made:

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

and

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

↙厌世 2024-11-16 08:07:30

如果您添加新组并同时将用户添加到组中,则上述保存方法将不起作用。问题是新组不会被保存(管理员使用 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

The save method above won't work if you add a new group and simultaneously add users to the group. The problem is that the new group won't get saved (the admin uses commit=False) and won't have a primary key. Since the purpose of save_m2m() is to allow the calling view to handle saving m2m objects, I made a save object that wraps the old save_m2m method in a new method.

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
同展鸳鸯锦 2024-11-16 08:07:30

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)

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)
墨小墨 2024-11-16 08:07:30

这是一种使用 Django 的 InlineModelAdmin 对象的更简单的方法(在这里回答曲伴诗.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)

Here is a simpler approach that uses Django's InlineModelAdmin objects (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)
卷耳 2024-11-16 08:07:30

我使用的是 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)

I am on Django 2.1 and was using the solution posted by Chris, but like explained by Cedric, it wouldn't work when when a new group was added and simultaneously users were added to the new group. Unfortunately, his code didn't help either, but I could get it to work using this modified version below.

Edit: I included the suggestion of user am70 (thanks!) and made use of get_user_model(). This code continues to work with Django 3.1 and has been tested with Python 3.6, 3.7 and 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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文