Разрешения на уровне строки в django

Есть ли способ сделать разрешения на уровне строк в django? Я думал, что это не так, а просто заметили это в документах:

Разрешения могут быть установлены не только для каждого типа объекта, но и для каждого конкретный экземпляр объекта. Используя has_add_permission(), Имеются методы has_change_permission() и has_delete_permission() классом ModelAdmin, можно настроить разрешения для разные экземпляры объектов того же типа.

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

Но я не вижу никакой документации о том, как реально реализовать разрешения на экземпляр

Ответы

Ответ 1

Для приложения, которое я создаю, я хочу предоставить разрешение на уровне строк через простой декоратор. Я могу сделать это, потому что условие заключается только в том, является ли 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):
    ...

Urls:

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

Любые отзывы или замечания приветствуются.

Пол Борман

Ответ 2

Способы, о которых говорят документы, позволят вам ограничить доступ к определенным объектам в admin. Каждому методу передается объект в игре, который вы можете использовать для определения того, может ли пользователь получить к нему доступ, возвращая либо True, либо 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

Ответ 3

Сантехника там (это со дна той же страницы, которую вы связали):

Обработка разрешений объектов

Структура разрешения Django имеет основание для прав объекта, хотя реализация отсутствует для этого в ядре. Это означает, что проверка прав объекта всегда будет возвращать False или пустой список (в зависимости от проверки выполнено). Бэкэнд аутентификации получит ключевое слово параметры obj и user_obj для каждого связанного с объектами разрешения метод и может при необходимости вернуть разрешение на уровне объекта.

Но реализация по умолчанию не предусмотрена. Поскольку это общая тема; есть много ответов на SO. Проверьте вправо, и вы увидите некоторые из них.

Основная идея состоит в том, чтобы просмотреть сетку разрешений django пакетов и выбрать реализацию разрешений уровня объекта. Мне лично нравится django-guardian.

Ответ 5

Существует большое количество приложений "разрешений" для django доступно на PyPi
Например, вы можете посмотреть django-object-permission.

В документации, на которую ссылается документация, есть функциональность для реализации разрешений. И люди сделали это, создав приложения для этого.