21

我有一个拥有庞大客户群的 django 网站。我想让我们的客户服务部门能够更改普通用户帐户,例如更改密码、电子邮件地址等。但是,如果我授予某人内置auth | user | Can change user权限,他们就可以is_superuser在任何用户上设置标志帐户,包括他们自己的帐户。(!!!)

为非超级用户员工删除此选项的最佳方法是什么?我确信它涉及子类django.contrib.auth.forms.UserChangeForm化并将其连接到我已经自定义的UserAdmin对象中......不知何故。但是我找不到任何有关如何执行此操作的文档,而且我还不太了解内部结构。

4

5 回答 5

24

他们能够在任何帐户上设置 is_superuser 标志,包括他们自己的。(!!!)

不仅如此,他们还获得了一个一个给自己任何权限的能力,同样的效果......

我确定它涉及子类化 django.contrib.auth.forms.UserChangeForm

嗯,不一定。您在 django 的 admin 的更改页面中看到的表单是由 admin 应用程序动态创建的,并且基于UserChangeForm,但是这个类几乎没有向该username字段添加正则表达式验证。

并将其连接到我已经自定义的 UserAdmin 对象中......

习惯UserAdmin是去这里的方式。基本上,您想将fieldsets属性更改为类似的内容:

class MyUserAdmin(UserAdmin):
    fieldsets = (
        (None, {'fields': ('username', 'password')}),
        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
        # Removing the permission part
        # (_('Permissions'), {'fields': ('is_staff', 'is_active', 'is_superuser', 'user_permissions')}),
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
        # Keeping the group parts? Ok, but they shouldn't be able to define
        # their own groups, up to you...
        (_('Groups'), {'fields': ('groups',)}),
    )

但这里的问题是这个限制将适用于所有用户。如果这不是您想要的,例如,您可以change_view根据用户的权限覆盖以采取不同的行为。代码片段:

class MyUserAdmin(UserAdmin):
    staff_fieldsets = (
        (None, {'fields': ('username', 'password')}),
        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
        # No permissions
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
        (_('Groups'), {'fields': ('groups',)}),
    )

    def change_view(self, request, *args, **kwargs):
        # for non-superuser
        if not request.user.is_superuser:
            try:
                self.fieldsets = self.staff_fieldsets
                response = super(MyUserAdmin, self).change_view(request, *args, **kwargs)
            finally:
                # Reset fieldsets to its original value
                self.fieldsets = UserAdmin.fieldsets
            return response
        else:
            return super(MyUserAdmin, self).change_view(request, *args, **kwargs)
于 2010-02-19T17:20:07.083 回答
8

接受的答案的以下部分有一个竞争条件,如果两个员工用户尝试同时访问管理表单,其中一个可能会获得超级用户表单。

try:
    self.readonly_fields = self.staff_self_readonly_fields
    response = super(MyUserAdmin, self).change_view(request, object_id, form_url, extra_context, *args, **kwargs)
finally:
    # Reset fieldsets to its original value
    self.fieldsets = UserAdmin.fieldsets

为了避免这种竞争条件(并且在我看来可以提高解决方案的整体质量),我们可以直接覆盖get_fieldsets()andget_readonly_fields()方法:

class UserAdmin(BaseUserAdmin):
    staff_fieldsets = (
        (None, {'fields': ('username')}),
        ('Personal info', {'fields': ('first_name', 'last_name', 'email')}),
        # No permissions
        ('Important dates', {'fields': ('last_login', 'date_joined')}),
    )
    staff_readonly_fields = ('username', 'first_name', 'last_name', 'email', 'last_login', 'date_joined')

    def get_fieldsets(self, request, obj=None):
        if not request.user.is_superuser:
            return self.staff_fieldsets
        else:
            return super(UserAdmin, self).get_fieldsets(request, obj)

    def get_readonly_fields(self, request, obj=None):
        if not request.user.is_superuser:
            return self.staff_readonly_fields
        else:
            return super(UserAdmin, self).get_readonly_fields(request, obj)
于 2017-03-30T21:12:56.543 回答
2

非常感谢克莱门特。当我为我的网站做同样的事情时,我想出的是,我还需要为除自己之外的用户设置所有字段只读。因此,根据克莱门特的回答,我在查看非自我时添加了只读字段和密码字段隐藏

class MyUserAdmin(UserAdmin):
    model = User
    staff_self_fieldsets = (
        (None, {'fields': ('username', 'password')}),
        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
        # No permissions
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
    )

    staff_other_fieldsets = (
        (None, {'fields': ('username', )}),
        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
        # No permissions
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
    )

    staff_self_readonly_fields = ('last_login', 'date_joined')

    def change_view(self, request, object_id, form_url='', extra_context=None, *args, **kwargs):
        # for non-superuser
        if not request.user.is_superuser:
            try:
                if int(object_id) != request.user.id:
                    self.readonly_fields = User._meta.get_all_field_names()
                    self.fieldsets = self.staff_other_fieldsets
                else:
                    self.readonly_fields = self.staff_self_readonly_fields
                    self.fieldsets = self.staff_self_fieldsets

                response = super(MyUserAdmin, self).change_view(request, object_id, form_url, extra_context, *args, **kwargs)
            except:
                logger.error('Admin change view error. Returned all readonly fields')

                self.fieldsets = self.staff_other_fieldsets
                self.readonly_fields = ('first_name', 'last_name', 'email', 'username', 'password', 'last_login', 'date_joined')
                response = super(MyUserAdmin, self).change_view(request, object_id, form_url, extra_context, *args, **kwargs)
            finally:
                # Reset fieldsets to its original value
                self.fieldsets = UserAdmin.fieldsets
                self.readonly_fields = UserAdmin.readonly_fields
            return response
        else:
            return super(MyUserAdmin, self).change_view(request, object_id, form_url, extra_context, *args, **kwargs)
于 2016-03-09T16:45:33.647 回答
1

This approach was put together from several helpful tips on the web. In this case we are modifying UserAdmin so that, for non-superuser staff with user add/change permission, the only permissions and groups they can grant another user are the ones the staff member already has.

(for Django 1.11)

from django.contrib.auth.admin import UserAdmin, User
from django.contrib import admin

class RestrictedUserAdmin(UserAdmin):
    model = User

    def formfield_for_dbfield(self, db_field, **kwargs):
        field = super(RestrictedUserAdmin, self).formfield_for_dbfield(db_field, **kwargs)
        user = kwargs['request'].user
        if not user.is_superuser:
            if db_field.name == 'groups':
                field.queryset = field.queryset.filter(id__in=[i.id for i in user.groups.all()])
            if db_field.name == 'user_permissions':
                field.queryset = field.queryset.filter(id__in=[i.id for i in user.user_permissions.all()])
            if db_field.name == 'is_superuser':
                field.widget.attrs['disabled'] = True
        return field

admin.site.unregister(User)
admin.site.register(User, RestrictedUserAdmin)

This should likewise be done for GroupAdmin if a user is given permission to change groups.

于 2019-02-21T15:08:44.140 回答
0

django 1.1 的完整代码(仅限于员工(非超级用户)的基本用户信息)

from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _


class MyUserAdmin(UserAdmin):
   my_fieldsets = (
       (None, {'fields': ('username', 'password')}),
       (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
   )

   def change_view(self, request, object_id, extra_context=None):
       # for non-superuser
       print 'test'
       if not request.user.is_superuser:
           self.fieldsets = self.my_fieldsets
           response = UserAdmin.change_view(self, request, object_id,
extra_context=None)
           return response
       else:
           return UserAdmin.change_view(self, request, object_id,
extra_context=None)


admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)
于 2010-08-12T20:17:13.967 回答