row level permissions in django

后端 未结 5 1885
一个人的身影
一个人的身影 2021-01-30 15:19

Is there a way to do row level permissions in django? I thought there wasn\'t but just noticed this in the docs:

Permissions can be set not only per type

相关标签:
5条回答
  • 2021-01-30 15:23

    There are a large number of "permissions" apps for django available on PyPi
    For example you could look at django-object-permission.

    What the documentation is referring to is that the functionality is there to implement the permissions. And people have done just that by creating apps for this.

    0 讨论(0)
  • 2021-01-30 15:35

    The methods that the docs talk about will allow you to restrict access to particular objects in the admin. Each method is passed the object in play, which you can use to make determinations about whether a user can access it, by returning either True or False.

    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
    
    0 讨论(0)
  • 2021-01-30 15:38

    For an application i'm building i want to provide row level permission through a simple decorator. I can do this because the condition is just whether the request.user is the owner of the model object.

    Following seems to work:

    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
    

    The view:

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

    Urls:

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

    The model:

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

    Any feedback or remarks are appreciated.

    Paul Bormans

    0 讨论(0)
  • 2021-01-30 15:38

    The plumbing is there (this is from the bottom of the same page you linked):

    Handling object permissions

    Django's permission framework has a foundation for object permissions, though there is no implementation for it in the core. That means that checking for object permissions will always return False or an empty list (depending on the check performed). An authentication backend will receive the keyword parameters obj and user_obj for each object related authorization method and can return the object level permission as appropriate.

    But no default implementation is provided. Since this is a common topic; there are lots of answers on SO. Check to the right and you'll see some listed.

    The basis idea is to browse the django packages' perm grid and pick an implementation of object level permissions. I personally like django-guardian.

    0 讨论(0)
  • 2021-01-30 15:46

    I have rolled-out a solution to this kind of problem using Django Class Based Views.

    Check out my article Django Generic Class Based Views with Object-Level Permissions Checking.

    0 讨论(0)
提交回复
热议问题