Django用户层次结构

时间:2011-11-11 14:41:37

标签: django panel admin hierarchy

我要创建一个可以实现用户层次结构的Web应用程序。我想这样做: 1.超级用户使用户(具有一些权限),也可以添加用户(仅具有他们拥有的权限)。此用户还可以添加用户等。没有人应该能够编辑拥有更多权限的用户。

问题在于我想为所有这些用户提供Django管理面板。甚至可以制作这样的东西吗?我搜索过网络并没有找到解决方案。谢谢你的建议。

3 个答案:

答案 0 :(得分:2)

如果要控制创建的用户权限,则需要为添加用户创建自己的视图。在Django管理站点上,任何可以创建用户的用户都可以创建超级用户。

来自creating users上的Django文档:

  

如果您希望自己的用户帐户能够使用Django管理站点创建用户,则需要允许自己添加用户和更改用户(即“添加用户”和“更改用户”权限) )。如果您的帐户有权添加用户但不能更改用户,则无法添加用户。为什么?因为如果您有权添加用户,则可以创建超级用户,然后可以更改其他用户。所以Django需要添加和更改权限作为一种轻微的安全措施。

答案 1 :(得分:2)

每个需要访问管理员的用户都必须拥有is_staff=True标记。允许与您的组织无关联的用户访问管理员是永远不的好主意。说真的,就是不要这样做。如果这是你的计划,那就找另一个。

那说,它可以做到,但它不适合胆小的人。涉及很多。第一个子类是默认的UserCreationFormUserChangeForm(Auth为它的管理员使用两个单独的表单)。覆盖每个__init__方法从request中提取kwargs(默认情况下表单不会获取请求,但这里有必要,所以你必须做一些解决方法。)然后,将默认UserAdmin子类化,将formadd_form设置为新表单并覆盖get_form(以传递request)和每个限制访问的has_foo_permission方法。 queryset方法也需要覆盖,因此用户只能看到他们可以在管理员中修改的用户。

from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth.models import Group, Permission

class CustomUserCreationForm(UserCreationForm):
    class Meta(UserCreationForm.Meta):
        pass

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)

        super(CustomUserCreationForm, self).__init__(*args, **kwargs)

        # Limit groups and permissions to those that belong to current user
        if self.request and not self.request.user.is_superuser:
            self.fields['groups'].queryset = self.request.user.groups.all()
            self.fields['user_permissions'].queryset = self.request.user.user_permissions.all()

 class CustomUserChangeForm(UserChangeForm):
    class Meta(UserChangeForm.Meta):
        pass

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)

        super(CustomUserChangeForm, self).__init__(*args, **kwargs)

        # Limit groups and permissions to those that belong to current user
        if self.request and not self.request.user.is_superuser:
            self.fields['groups'].queryset = self.request.user.groups.all()
            self.fields['user_permissions'].queryset = self.request.user.user_permissions.all()

class CustomUserAdmin(UserAdmin):
    form = UserChangeForm
    add_form = UserCreationForm

    limited_fieldsets = ( # Copied from default `UserAdmin`, but removed `is_superuser`
        (None, {'fields': ('username', 'password')}),
        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
        (_('Permissions'), {'fields': ('is_active', 'is_staff', 'user_permissions')}),
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
        (_('Groups'), {'fields': ('groups',)}),
    )

    def get_fieldsets(self, request, obj=None):
        if not obj:
            return self.add_fieldsets
        elif not request.user.is_superuser:
            return self.limited_fieldsets
        else:
            return super(CustomUserAdmin, self).get_fieldsets(request, obj)

    def get_form(self, request, obj=None, **kwargs):
        """Return a metaclass that will automatically pass `request` kwarg into the form"""
        ModelForm = super(LinkAdmin, self).get_form(request, obj, **kwargs)
        class ModelFormMetaClass(ModelForm):
            def __new__(cls, *args, **kwargs):
                kwargs['request'] = request
                return ModelForm(*args, **kwargs)
        return ModelFormMetaClass

    def has_add_permission(self, request):
        """
        If not superuser only allow add if the current user has at least some
        groups or permissions. (they'll have to be able to at least have something
        to assign the user they are creating).
        """
        if not request.user.is_superuser:
            if not request.user.groups.exists() or not request.user.user_permissions.exist():
                return False

        return True


    def has_change_permission(self, request, obj=None):
        """
        If not superuser, current user can only modify users who have a subset of the
        groups and permissions they have.
        """

        if obj and not request.user.is_superuser:
            # Check that all of the object's groups are in the current user's groups
            user_groups = list(request.user.groups.all())
            for group in obj.groups.all():
                try:
                    user_groups.index(group)
                except ValueError:
                    return False

            # Check that all of the object's permissions are in the current user's permissions
            user_permissions = list(request.user.user_permissions.all())
            for permission in obj.user_permissions.all():
                try:
                    user_permissions.index(permission)
                except ValueError:
                    return False

        return True

    def has_delete_permission(self, request, obj=None):
        """Same logic as `has_change_permission`"""
        return self.has_change_permission(request, obj)

    def queryset(self, request):
        qs = super(CustomUserAdmin, self).queryset(self, request)

        if request.user.is_superuser:
            return qs
        else:
            """
            This part is a little counter-intuitive. We're going to first get a
            list of all groups/permissions that don't belong to the user, and
            then use that to exclude users that do have those from the queryset.
            """

            user_group_pks = [g.pk for g request.user.groups.values('pk')]
            exclude_groups = Group.objects.exclude(pk__in=user_group_pks)

            user_permission_pks = [p.pk for p in request.user.user_permissions.values('pk')]
            exclude_permissions = Permission.objects.exclude(pk__in=user_permission_pks)

            return qs.exclude(groups__in=exclude_groups, user_permissions__in=exclude_permissions)

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

答案 2 :(得分:1)

Django包含一个用于维护用户层次结构的内置系统--Django-RBAC。

RBAC代表 基于角色的访问控制 。它是一种基于层次结构创建和管理权限的机制。你只需要研究一下。