21

有没有办法在 django 中执行行级权限?我以为没有,但只是在文档中注意到了这一点:

不仅可以按对象类型设置权限,还可以按特定对象实例设置权限。通过使用 ModelAdmin 类提供的 has_add_permission()、has_change_permission() 和 has_delete_permission() 方法,可以为同一类型的不同对象实例自定义权限。

https://docs.djangoproject.com/en/dev/topics/auth/

但我没有看到任何关于如何实际实现每个实例权限的文档

4

5 回答 5

27

对于我正在构建的应用程序,我想通过一个简单的装饰器提供行级权限。我可以这样做,因为条件只是 request.user 是否是模型对象的所有者。

以下似乎工作:

from functools import wraps
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist

def is_owner_permission_required(model, pk_name='pk'):
    def decorator(view_func):
        def wrap(request, *args, **kwargs):
            pk = kwargs.get(pk_name, None)
            if pk is None:
                raise RuntimeError('decorator requires pk argument to be set (got {} instead)'.format(kwargs))
            is_owner_func = getattr(model, 'is_owner', None)
            if is_owner_func is None:
                raise RuntimeError('decorator requires model {} to provide is_owner function)'.format(model))
            o=model.objects.get(pk=pk) #raises ObjectDoesNotExist
            if o.is_owner(request.user):
                return view_func(request, *args, **kwargs)
            else:
                raise PermissionDenied
        return wraps(view_func)(wrap)
    return decorator

风景:

@login_required
@is_owner_permission_required(Comment)
def edit_comment(request, pk):
    ...

网址:

url(r'^comment/(?P<pk>\d+)/edit/$', 'edit_comment'),

该模型:

class Comment(models.Model):
    user = models.ForeignKey(User, ...
    <...>
    def is_owner(self, user):
        return self.user == user

任何反馈或评论表示赞赏。

保罗·博尔曼斯

于 2012-12-02T17:48:53.123 回答
7

管道在那里(这是您链接的同一页面的底部):

处理对象权限

Django 的权限框架为对象权限奠定了基础,尽管核心中没有实现它。这意味着检查对象权限将始终返回 False 或空列表(取决于执行的检查)。身份验证后端将接收每个对象相关授权方法的关键字参数 obj 和 user_obj,并可以适当地返回对象级别的权限。

但是没有提供默认实现。因为这是一个共同的话题;SO上有很多答案。检查右侧,您会看到一些列表。

基本思想是浏览django 包的 perm 网格并选择对象级权限的实现。我个人喜欢django-guardian

于 2012-08-09T20:47:02.903 回答
7

文档讨论的方法将允许您限制对管理员中特定对象的访问。每个方法都传递给正在运行的对象,您可以使用它来确定用户是否可以访问它,方法是返回TrueFalse

class MyModelAdmin(admin.ModelAdmin):
    ...
    def has_add_permission(self, request):
        # This one doesn't get an object to play with, because there is no
        # object yet, but you can still do things like:
        return request.user.is_superuser
        # This will allow only superusers to add new objects of this type

    def has_change_permission(self, request, obj=None):
        # Here you have the object, but this is only really useful if it has
        # ownership info on it, such as a `user` FK
        if obj is not None:
            return request.user.is_superuser or \
                   obj.user == request.user
            # Now only the "owner" or a superuser will be able to edit this object
        else:
            # obj == None when you're on the changelist page, so returning `False`
            # here will make the changelist page not even viewable, as a result,
            # you'd want to do something like:
            return request.user.is_superuser or \
                   self.model._default_manager.filter(user=request.user).exists()
            # Then, users must "own" *something* or be a superuser or they
            # can't see the changelist

    def has_delete_permission(self, request, obj=None):
        # This pretty much works the same as `has_change_permission` only
        # the obj == None condition here affects the ability to use the
        # "delete selected" action on the changelist
于 2012-08-09T21:10:47.723 回答
1

我已经使用 Django 基于类的视图推出了针对此类问题的解决方案。

查看我的文章Django Generic Class Based Views with Object-Level Permissions Checking

于 2013-09-30T18:26:08.750 回答
0

PyPi 上有大量适用于 django 的“权限”应用程序,
例如,您可以查看django-object-permission

文档所指的是实现权限的功能。人们通过为此创建应用程序来做到这一点。

于 2012-08-09T20:46:10.817 回答