如何限制员工用户只能在 Django 管理页面中查看他们的信息?

Posted

技术标签:

【中文标题】如何限制员工用户只能在 Django 管理页面中查看他们的信息?【英文标题】:How to restrict access for staff users to see only their information in Django admin page? 【发布时间】:2019-10-07 15:12:33 【问题描述】:

我创建了一个自定义 Django 管理页面。我有两种类型的用户可以访问管理页面(员工用户和超级用户)。超级用户可以查看所有用户并可以更改他们的设置。他还可以添加或删除用户。员工用户只能看到他们的设置并且可以更改其中的一些。我目前有一个问题,员工用户可以看到 Web 应用程序的所有用户并且可以添加或删除他们。我限制员工用户查看某些设置,但无法更改。

我不知道如何限制员工用户只能看到他们的设置。

这是我的代码: 管理员.py

from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin

from .forms import UserAdminChangeForm, UserAdminCreationForm
from .models import UpLoadFile

User = get_user_model()

admin.site.site_header = 'SRC Orkestracija'
admin.site.index_title = 'Administration'
admin.site.register(UpLoadFile)


class UserAdmin(BaseUserAdmin):
    # The forms to add and change user instances
    form = UserAdminChangeForm
    add_form = UserAdminCreationForm

    # The fields to be used in displaying the User model.
    # These override the definitions on the base UserAdmin
    # that reference specific fields on auth.User.
    list_display = ('username', 'superuser', 'active', 'staff')
    list_filter = ('superuser', 'active', 'staff')
    readonly_fields = [
        'last_login'
    ]
    actions = [
        'activate_users',
    ]
    filter_horizontal = ('user_permissions', 'groups')

    fieldsets = (
        (None, 'fields': ('username', 'password', 'config_file')),
        ('Permissions', 'fields': ('superuser', 'active', 'staff', 'groups', 'user_permissions')),
        ('Important dates', 'fields': ('last_login',)),
    )
    # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
    # overrides get_fieldsets to use this attribute when creating a user.
    add_fieldsets = (
        (None, 
            'classes': ('wide',),
            'fields': ('username', 'password1', 'password2', 'config_file')
         ),
    )
    search_fields = ('username',)
    ordering = ('username',)

    def get_form(self, request, obj=None, **kwargs):
        form = super().get_form(request, obj, **kwargs)
        is_superuser = request.user.is_superuser
        disabled_fields = set()

        if not is_superuser:
            disabled_fields |= 
                'username',
                'active',
                'superuser',
                'staff',
                'groups',
                'user_permissions'
            
            if (
                    not is_superuser
                    and obj is not None
                    and obj == request.user
            ):
                disabled_fields |= 
                    'username',
                    'active',
                    'superuser',
                    'staff',
                    'groups',
                    'user_permissions'
                

            for f in disabled_fields:
                if f in form.base_fields:
                    form.base_fields[f].disabled = True
        return form

    def activate_users(self, request, queryset):
        is_superuser = request.user.is_superuser
        if is_superuser:
            cnt = queryset.filter(active=False).update(active=True)
            self.message_user(request, 'Activated  users.'.format(cnt))

    activate_users.short_description = 'Activate Users'


admin.site.register(User, UserAdmin)

模型.py:

class UserManager(BaseUserManager):
    def create_user(self, username, config_file, password=None, is_active=True, is_staff=False, is_superuser=False):
        if not username:
            raise ValueError("User must have username!")
        if not password:
            raise ValueError("User must have password!")
        if not config_file:
            raise ValueError("Select config file!")
        user_obj = self.model(
            username=username,
        )
        user_obj.config_file = config_file
        user_obj.staff = is_staff
        user_obj.superuser = is_superuser
        user_obj.active = is_active
        user_obj.set_password(password)
        user_obj.save(using=self._db)
        return user_obj

    def create_staffuser(self, username, config_file, password=None):
        user = self.create_user(
            username=username,
            config_file=config_file,
            password=password,
            is_staff=True
        )
        return user

    def create_superuser(self, username, config_file, password=None):
        user = self.create_user(
            username=username,
            config_file=config_file,
            password=password,
            is_staff=True,
            is_superuser=True
        )
        return user


class CustomUser(AbstractBaseUser, PermissionsMixin):
    class Meta:
        verbose_name = "User"
        verbose_name_plural = "Users"

    OPTIONS = (
        ('1', '1'),
        ('2', '2'),
        ('3', '3'),
        ('4', '4'),
    )
    username = models.CharField(unique=True, max_length=255)
    active = models.BooleanField(default=True,
                                 help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.')
    staff = models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.')
    superuser = models.BooleanField(default=False,
                                    help_text='Designates that this user has all permissions without explicitly assigning them.')
    config_file = models.CharField(choices=OPTIONS, max_length=255)

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['config_file']

    object = UserManager()

    def __str__(self):
        return self.username

    def has_perm(self, perm, obj=None):
        return True

    def has_module_perms(self, app_lable):
        return True

    @property
    def is_staff(self):
        return self.staff

    @property
    def is_superuser(self):
        return self.superuser

    @property
    def is_active(self):
        return self.active


def path(user, filename):
    return os.path.join(str(user))

我将不胜感激任何帮助或说明如何添加此功能。

【问题讨论】:

首先,使用has_change_permission()has_view_permission()等方法,根据登录的用户完全阻止查看/更改某些用户的访问。然后,如果您想更改可以编辑的字段,设置 disabled 是正确的,但我不明白您的逻辑,因为您将相同的字段两次添加到您的集合中。 【参考方案1】:

您可以将超级用户设置为仅在管理类中具有添加/删除权限。

class UserAdmin(BaseUserAdmin):
    ...
    def has_add_permission(self, request, obj=None):
        return request.user.is_superuser

    def has_delete_permission(self, request, obj=None):
        return request.user.is_superuser

请注意,通过不在管理界面中向任何组或用户授予添加或删除权限也可以实现上述目标。

以下将只允许用户更改所有用户,如果他们是超级用户。否则,他们将只能更改自己的用户。

    def has_change_permission(self, request, obj=None):
        return request.user.is_superuser or (obj and obj.id == request.user.id)

如果您希望他们能够看到只有他们的用户可见的用户列表页面,您可以修改get_queryset

    def get_queryset(self, request):
        qs = super().get_queryset(request)
        user = request.user
        return qs if user.is_superuser else qs.filter(id=user.id)

【讨论】:

在这个 if 语句 if obj.id == request.user.id: 我得到 'NoneType' object has no attribute 'id'。我做错了什么? @MihaelWaschl if obj and obj.id == request.user.id: 如果您要添加新对象,obj 将不存在,将是 None。我的错误,我会更新我的答案 我注意到,如果你重写 get_queryset 方法,当用户传递一些搜索参数时,会显示那些受限对象。 @IgorisSkinderis 关于搜索参数,您有什么建议?从请求中删除它们?【参考方案2】:

在您的模板中:

% if request.user.is_superuser %
<!-- Only superusers can view things in here -->
% endif %

在您看来,您还必须控制哪些内容可以编辑,哪些内容不能。

【讨论】:

覆盖模板或视图并不是管理员更改表单最简单的事情。在这种情况下不推荐,因为您必须手动呈现表单字段,这会破坏 ModelAdmin 的整个表单构建逻辑。

以上是关于如何限制员工用户只能在 Django 管理页面中查看他们的信息?的主要内容,如果未能解决你的问题,请参考以下文章

Django第二课 基于Django超市订单管理系统开发

Django第二课 基于Django超市订单管理系统开发

如何只允许管理员(或某些用户)在 Django 中编辑页面?

如何将 Django Rest Framework 可浏览 API 接口限制为管理员用户

Django admin - 模型对超级用户可见,而不是员工用户

Django第四课 基于Django超市订单管理系统开发